import { RawSearchRequest, RecommendationsResponse, RequestType, SearchRequest, SearchResponse } from '../models'; import { ItemType } from '../models/base.models'; import { AutocompleteService, ConversationalService, RecommendationsService, SearchService, TrackingService } from '../services'; import * as Handlebars from 'handlebars'; export interface BaseComponentConfig { /** * Specifies whether the component should be rendered in the [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM). This is highly recommended to avoid CSS conflicts. * * #### Default Value * `true` */ shadowDom?: boolean; /** * Specifies a custom template to be used instead of the default template. * * *For more information, see {@link Components}.* */ template?: string; /** * Specifies whether the component should be rendered in the avoid injecting the * css to head of the page. This would only effect when shadowDom false */ useCustomStyle?: boolean; } export interface AutocompleteComponentConfig extends BaseComponentConfig { /** * Specifies whether the component should still render — so a custom template can display fallback content — when the autocomplete response has no results. Has no effect until an autocomplete response has been received. * * #### Default Value * `false` */ showAlways?: boolean; } export interface CheckboxListFacetComponentConfig extends BaseComponentConfig { excludeEnabled?: boolean; strings?: { collapse?: string; exclude?: string; expand?: string; include?: string; showFewer?: string; showMore?: string; }; } export interface ColorFacetComponentConfig extends BaseComponentConfig { excludeEnabled?: boolean; strings?: { exclude?: string; include?: string; showFewer?: string; showMore?: string; }; } export interface ContentZoneComponentConfig extends BaseComponentConfig { } export interface BubbleContentComponentConfig extends BaseComponentConfig { } export interface ConversationalSearchComponentConfig extends BaseComponentConfig { query?: string; strings?: { /** * #### Default Value * `Enter a message...` */ placeholder?: string; /** * #### Default Value * `Reset` */ reset?: string; /** * #### Default Value * `Send` */ send?: string; }; prompt?: { /** * #### Default Value * ` * You are a recommendation agent, specialized in finding the perfect match for a user. * Answer the question from the user extensivelly. * You will be provided with an array of products as DATA. * Create 2 suggested questions that a user could ask about this data that follows. * Use new lines to seperate them. Make them short. * Say something like 'Try one of these suggested questions:' followed by the questions you generate. * Only use the information passed to you as DATA to answer the questions asked. * Do not provide any information on amount of DATA you currently have. * ` */ instructions?: string; }; } export interface CustomContentComponentConfig extends BaseComponentConfig { } export interface DatePickerComponentConfig extends BaseComponentConfig { strings?: { defaultLabel?: string; next?: string; previous?: string; selectMonth?: string; viewCalendar?: string; }; } export interface DateRangeFacetComponentConfig extends BaseComponentConfig { strings?: { endDate?: string; startDate?: string; }; } export interface FacetsListComponentConfig extends BaseComponentConfig { strings?: { heading?: string; }; } export interface FacetWrapperComponentConfig extends BaseComponentConfig { } export interface FeaturedItemsContentComponentConfig extends BaseComponentConfig { } export interface FeaturedItemsContentItemComponentConfig extends BaseComponentConfig { strings?: { sale?: string; }; } export interface IconComponentConfig extends BaseComponentConfig { } export interface ImageContentComponentConfig extends BaseComponentConfig { } export interface LandingPageComponentConfig extends BaseComponentConfig { } export interface LinkListFacetComponentConfig extends BaseComponentConfig { strings?: { showFewer?: string; showMore?: string; }; } export interface ModifiedQueryComponentConfig extends BaseComponentConfig { strings?: { showingResultsFor?: string; searchInsteadFor?: string; }; } export interface NumericRangeFacetComponentConfig extends BaseComponentConfig { /** * The number of decimal places to display in the range inputs and to round the submitted facet value to. Use this for facets whose values are decimals (e.g. `2` for currency). * * #### Default Value * `0` */ precision?: number; strings?: { maximum?: string; minimum?: string; }; } export interface PageSizeComponentConfig extends BaseComponentConfig { } export interface PaginationComponentConfig extends BaseComponentConfig { strings?: { first?: string; last?: string; next?: string; previous?: string; summary?: string; }; } export interface PopularQueriesContentComponentConfig extends BaseComponentConfig { } export interface QuerySuggestionsComponentConfig extends BaseComponentConfig { strings?: { orDelimeter?: string; prompt?: string; }; } export interface RangeSliderComponentConfig extends BaseComponentConfig { strings?: { end?: string; start?: string; }; } export interface RangeSliderFacetComponentConfig extends BaseComponentConfig { /** * The number of decimal places to display in the range inputs and to round the submitted facet value to. Use this for facets whose values are decimals (e.g. `2` for currency). * * #### Default Value * `0` */ precision?: number; strings?: { maximum?: string; minimum?: string; }; } export interface RatingComponentConfig extends BaseComponentConfig { } export interface RecentSearchesFacetComponentConfig extends BaseComponentConfig { } export interface RecommendationsItemComponentConfig extends BaseComponentConfig { strings?: { sale?: string; }; } export interface RecommendationsComponentConfig extends BaseComponentConfig { carousel?: { autorotation?: { enabled?: boolean; interval?: number; }; buttonsEnabled?: boolean; enabled?: boolean; paginationEnabled?: boolean; paginationSelectedCssClass?: string; }; headingEnabled?: boolean; itemsToDisplay?: Breakpoints; strings?: { next?: string; previous?: string; }; } export interface RelatedSearchesFacetComponentConfig extends BaseComponentConfig { } export interface SearchFieldComponentConfig extends BaseComponentConfig { strings?: { placeholder?: string | Array; }; /** * Specifies whether the input element should be pre-populared if "query" parameter exists on the URL. * * #### Default Value * `false` */ disableAutofill?: boolean; /** * Specifies whether the placeholder animation should be disabled. When `true` and the placeholder is an array, a random item will be selected instead of animating. * * #### Default Value * `false` */ disablePlaceholderAnimation?: boolean; /** * Specifies the debounce value between fetching data and keypress (ms) * * #### Default Value * `250` * *For more information, see {@link Components}.* */ searchDebounceValue?: number; } export interface ConceptSearchFieldComponentConfig extends BaseComponentConfig { strings?: { placeholder?: string | Array; }; /** * Specifies whether the input element should be pre-populared if "query" parameter exists on the URL. * * #### Default Value * `false` */ disableAutofill?: boolean; /** * Specifies whether the placeholder animation should be disabled. When `true` and the placeholder is an array, a random item will be selected instead of animating. * * #### Default Value * `false` */ disablePlaceholderAnimation?: boolean; /** * Specifies the debounce value between fetching data and keypress (ms) * * #### Default Value * `250` * *For more information, see {@link Components}.* */ searchDebounceValue?: number; /** * Specifies if a request is triggered on keypress. * * #### Default Value * `false` * *For more information, see {@link Components}.* */ searchOnKeyPress?: boolean; /** * Specifies the minimum length for a query to trigger a request. * * #### Default Value * `10` * *For more information, see {@link Components}.* */ searchMinCharacterCount?: number; } export interface ImageSearchFieldComponentConfig extends BaseComponentConfig { strings?: { placeholder?: string | Array; }; /** * Specifies whether the input element should be pre-populared if "query" parameter exists on the URL. * * #### Default Value * `false` */ disableAutofill?: boolean; /** * Specifies whether the placeholder animation should be disabled. When `true` and the placeholder is an array, a random item will be selected instead of animating. * * #### Default Value * `false` */ disablePlaceholderAnimation?: boolean; /** * Specifies the debounce value between fetching data and keypress (ms) * * #### Default Value * `250` * *For more information, see {@link Components}.* */ searchDebounceValue?: number; /** * Specifies if a request is triggered on keypress. * * #### Default Value * `false` * *For more information, see {@link Components}.* */ searchOnKeyPress?: boolean; /** * Specifies the minimum length for a query to trigger a request. * * #### Default Value * `10` * *For more information, see {@link Components}.* */ searchMinCharacterCount?: number; } export interface UnifiedSearchFieldComponentConfig extends BaseComponentConfig { strings?: { placeholder?: string | Array; }; /** * Specifies whether the input element should be pre-populared if "query" parameter exists on the URL. * * #### Default Value * `false` */ disableAutofill?: boolean; /** * Specifies whether the placeholder animation should be disabled. When `true` and the placeholder is an array, a random item will be selected instead of animating. * * #### Default Value * `false` */ disablePlaceholderAnimation?: boolean; /** * Specifies the debounce value between fetching data and keypress (ms) * * #### Default Value * `250` * *For more information, see {@link Components}.* */ searchDebounceValue?: number; /** * Specifies if a request is triggered on keypress. * * #### Default Value * `false` * *For more information, see {@link Components}.* */ searchOnKeyPress?: boolean; /** * Specifies the minimum length for a query to trigger a request. * * #### Default Value * `10` * *For more information, see {@link Components}.* */ searchMinCharacterCount?: number; } export interface VisualSearchFieldComponentConfig extends BaseComponentConfig { strings?: { /** * #### Default Value * `Drag an image here or ` * *For more information, see {@link Components}.* */ dragImageMessage?: string; /** * #### Default Value * `upload an image` * *For more information, see {@link Components}.* */ uploadImageMessage?: string; /** * #### Default Value * `Drop an image here` * *For more information, see {@link Components}.* */ dropImageMessage?: string; /** * #### Default Value * `Drop an image here` * *For more information, see {@link Components}.* */ errorMessage?: string; }; } export interface SearchResultsComponentConfig extends BaseComponentConfig { } export interface SearchResultsItemComponentConfig extends BaseComponentConfig { strings?: { sale?: string; }; } export interface SearchResultsListComponentConfig extends BaseComponentConfig { } export interface SearchWithinFacetComponentConfig extends BaseComponentConfig { strings?: { label?: string; }; } export interface SelectedFacetsComponentConfig extends BaseComponentConfig { strings?: { remove?: string; }; } export interface SizeFacetComponentConfig extends BaseComponentConfig { excludeEnabled?: boolean; strings?: { exclude?: string; include?: string; showFewer?: string; showMore?: string; }; } export interface SmartResponseComponentConfig extends BaseComponentConfig { strings?: { /** * #### Default Value * `SmartResponse` */ header?: string; /** * #### Default Value * `No Results found` */ noresults?: string; }; /** * Specifies the agent instructions provided to GenAI Bridge */ prompt?: { /** * #### Default Value * ` * You are a recommendation agent, specialized in finding the perfect match for a user. * Answer the question from the user extensivelly. * You will be provided with a user input and an array of products. * Based on the user input and products, determine a maximum of 3 of the most relevant products based on the user input. * Do not provide any information about amount of products you're returning. * ` */ instructions?: string; /** * #### Default Value * ` * { * "name": "smartresponse_summary", * "description": "Recommedation message and product details which includes name, description, url, price and imageUrl", * "strict": true, * "schema": { * "type": "object", * "properties": { * "recommendation": { * "type": "string" * }, * "products": { * "type": "array", * "items": { * "type": "object", * "properties": { * "name": { * "type": "string" * }, * "url": { * "type": "string" * }, * "description": { * "type": "string" * }, * "price": { * "type": "number" * }, * "imageUrl": { * "type": "string" * } * }, * "required": [ * "name", * "url", * "description", * "price", * "imageUrl" * ], * "additionalProperties": false * } * } * }, * "required": [ * "recommendation", * "products" * ], * "additionalProperties": false * } * } * ` */ schema?: object; }; defaultQuery?: { /** * #### Default Value * in case no user input is found, smart response component uses this * as default input */ input?: string; }; /** * Configuration for smartreponse expect the agentId, clientGroupId * and apiUrl. */ config: { /** * #### Required * The unique identifier for the smart response agent */ agentId: string; /** * #### Required * The client group ID for the smart response configuration */ clientGroupId: string; apiUrl?: string; searchEndpoint?: string; }; } export interface SortingComponentConfig extends BaseComponentConfig { } export interface TabsComponentConfig extends BaseComponentConfig { } export interface TooltipComponentConfig extends BaseComponentConfig { } export interface VariantSelectorComponentConfig extends BaseComponentConfig { } export interface HawkSearchComponents { 'autocomplete'?: AutocompleteComponentConfig; 'bubble-content'?: BubbleContentComponentConfig; 'checkbox-list-facet'?: CheckboxListFacetComponentConfig; 'color-facet'?: ColorFacetComponentConfig; 'concept-search-field'?: ConceptSearchFieldComponentConfig; 'content-zone'?: ContentZoneComponentConfig; 'conversational-search'?: ConversationalSearchComponentConfig; 'custom-content'?: CustomContentComponentConfig; 'date-picker'?: DatePickerComponentConfig; 'date-range-facet'?: DateRangeFacetComponentConfig; 'facet-wrapper'?: FacetWrapperComponentConfig; 'facets-list'?: FacetsListComponentConfig; 'featured-items-content'?: FeaturedItemsContentComponentConfig; 'featured-items-content-item'?: FeaturedItemsContentItemComponentConfig; 'icon'?: IconComponentConfig; 'image-content'?: ImageContentComponentConfig; 'image-search-field'?: ImageSearchFieldComponentConfig; 'landing-page'?: LandingPageComponentConfig; 'link-list-facet'?: LinkListFacetComponentConfig; 'modified-query'?: ModifiedQueryComponentConfig; 'no-results'?: NoResultsComponentConfig; 'numeric-range-facet'?: NumericRangeFacetComponentConfig; 'page-size'?: PageSizeComponentConfig; 'pagination'?: PaginationComponentConfig; 'popular-queries-content'?: PopularQueriesContentComponentConfig; 'query-suggestions'?: QuerySuggestionsComponentConfig; 'range-slider'?: RangeSliderComponentConfig; 'range-slider-facet'?: RangeSliderFacetComponentConfig; 'rating'?: RatingComponentConfig; 'recommendations'?: RecommendationsComponentConfig; 'recommendations-item'?: RecommendationsItemComponentConfig; 'recent-searches-facet'?: RecentSearchesFacetComponentConfig; 'related-searches-facet'?: RelatedSearchesFacetComponentConfig; 'search-field'?: SearchFieldComponentConfig; 'search-results'?: SearchResultsComponentConfig; 'search-results-item'?: SearchResultsItemComponentConfig; 'search-results-list'?: SearchResultsListComponentConfig; 'search-within-facet'?: SearchWithinFacetComponentConfig; 'selected-facets'?: SelectedFacetsComponentConfig; 'size-facet'?: SizeFacetComponentConfig; 'smart-response'?: SmartResponseComponentConfig; 'sorting'?: SortingComponentConfig; 'tabs'?: TabsComponentConfig; 'tooltip'?: TooltipComponentConfig; 'unified-search-field'?: UnifiedSearchFieldComponentConfig; 'variant-selector'?: VariantSelectorComponentConfig; 'visual-search-field'?: VisualSearchFieldComponentConfig; /** @deprecated Use `'concept-search-field'` instead. */ 'conceptsearch-field'?: ConceptSearchFieldComponentConfig; /** @deprecated Use `'conversational-search'` instead. */ 'conversationalsearch'?: ConversationalSearchComponentConfig; /** @deprecated Use `'image-search-field'` instead. */ 'imagesearch-field'?: ImageSearchFieldComponentConfig; /** @deprecated Use `'no-results'` instead. */ 'noresult'?: NoResultsComponentConfig; /** @deprecated Use `'smart-response'` instead. */ 'smartresponse'?: SmartResponseComponentConfig; /** @deprecated Use `'unified-search-field'` instead. */ 'unifiedsearch-field'?: UnifiedSearchFieldComponentConfig; /** @deprecated Use `'visual-search-field'` instead. */ 'visualsearch-field'?: VisualSearchFieldComponentConfig; } export type DisplayType = 'mobile' | 'tablet' | 'desktop'; export interface Breakpoints extends Record { } /** * Note: All field names are converted to lowercase; therefore, mappings should be referenced similarly regardless of their configuration in the Workbench. */ export interface FieldMappings { /** * #### Default Value * `['description', 'longdescription']` */ description?: string | Array; /** * #### Default Value * `['imageurl', 'image']` */ imageUrl?: string | Array; /** * #### Default Value * `'price'` */ price?: string | Array; /** * #### Default Value * `'rating'` */ rating?: string | Array; /** * #### Default Value * `['saleprice']` */ salePrice?: string | Array; /** * #### Default Value * `['sku']` */ sku?: string | Array; /** * #### Default Value * `['title', 'name', 'itemname']` */ title?: string | Array; /** * #### Default Value * `'type'` */ type?: string | Array; /** * #### Default Value * `'url'` */ url?: string; brand?: string | Array; } export interface VariantFieldMappings extends FieldMappings { /** * #### Default Value * `['id']` */ id?: string | Array; color?: { /** * #### Default Value * `['colorname', 'color']` */ name?: string | Array; /** * #### Default Value * `['colorhex', 'colorvalue']` */ hex?: string | Array; /** * #### Default Value * `['colorimageurl', 'colorimage']` */ imageUrl?: string | Array; }; } export interface HawkSearchConfig { /** * The unique ID for your installation found in the HawkSearch admin */ clientId: string; /** * Specify an index to query rather than the default */ index?: string; /** * Map item attributes to common object properties */ fieldMappings?: FieldMappings; autocomplete?: { /** * The API used to retrieve search results * * #### Default Value * `'https://searchapi-dev.hawksearch.net'` */ endpointUrl?: string; /** * Specifies whether autocomplete recommendations (autocomplete without entering a query - "instant engage") is enabled * * #### Default Value * `false` */ recommendationsEnabled?: boolean; /** * Whether to automatically URI decode the search query value. Runs recursively until value is fully decoded. For example, `Test%2520Value` would become `Test Value`. * * #### Default Value * `true` */ decodeQuery?: boolean; /** * Specifies the minimum length for a query to trigger an autocomplete recommendations request. * * #### Default Value * `1` */ minCharacterCount?: number; }; search?: { /** * The API used to retrieve search results * * #### Default Value * `'https://searchapi-dev.hawksearch.net'` */ endpointUrl?: string; /** * The URL of your search results page. This is used to redirect users after performing a search. * * #### Default Value * `'/search'` */ url?: string; /** * The prefix for values sent to the API when excluding a facet. This is only modified in rare circumstances where the project has facet values starting with a hyphen. * * #### Default Value * `'-'` */ facetExclusionPrefix?: string; /** * Specifies how search results should be classified */ itemTypes?: { /** * If the value a search result item is missing a value for the field mapped to {@link HawkSearchConfig.search | fieldMappings.type}, this value will be assumed. * * #### Default Value * `'content'` */ default: ItemType; /** * List of values that will be considered a `product` result. * * #### Default Value * `['item', 'product']` */ productValues?: Array; }; /** * Specifies which query string parameters are used */ queryStringMappings?: { /** * #### Default Value * `'disableSpellcheck'` */ disableSpellcheck?: string; /** * #### Default Value * `'page'` */ page?: string; /** * #### Default Value * `'pageSize'` */ pageSize?: string; /** * #### Default Value * `'query'` */ query?: string; /** * #### Default Value * `'searchWithin'` */ searchWithin?: string; /** * #### Default Value * `'sort'` */ sort?: string; /** * Sets RequestType field to toggle between Keyword search, Image search or Concept search * * #### Default Value * `'DefaultSearch'` */ requestType?: RequestType; }; /** * Whether to automatically URI decode the search query value. Runs recursively until value is fully decoded. For example, `Test%2520Value` would become `Test Value`. * * #### Default Value * `true` */ decodeQuery?: boolean; /** * Whether to automatically URI decode facet selection values. Runs recursively until value is fully decoded. For example, `Test%2520Value` would become `Test Value`. * * #### Default Value * `true` */ decodeFacetValues?: boolean; /** * This would allow hide and show the desktop banner on mobile and tablet * #### Default Value * true */ desktopOnlyBanner?: boolean; /** * Specifies a kValue for Concept and Image search */ kValue?: number; }; recommendations?: { /** * The API used to retrieve product recommendations * * #### Default Value * `'https://recs-dev.hawksearch.net'` */ endpointUrl?: string; /** * Specifies whether widget title should be used as title. As default it uses name attribute as title * * #### Default Value * * `false` */ useTitle?: boolean; }; tracking?: { /** * Specifies whether user actions should be tracked to provide valuable insights on your search engine performance * * #### Default Value * * `true` */ enabled?: boolean; /** * The API used to track user interactions * * #### Default Value * `'https://tracking-dev.hawksearch.net'` */ endpointUrl?: string; }; variants?: { /** * When `true`, specifies that facet counts should be calculated based on the number of child items rather than the number of parent items * * #### Default Value * * `false` */ baseFacetCountOnVariants?: boolean; /** * Specifies whether variant logic should be used if data is available * * #### Default Value * * `true` */ enabled?: boolean; /** * When specified, this prefix is removed from the `attributes` collection on variant items. For example, if a value of `'child_'` is used and HawkSearch returns a field named `'child_color'`, it will be transformed to `'color'`. */ fieldPrefix?: string; /** * Map item attributes to common object properties */ fieldMappings?: VariantFieldMappings; /** * When `true`, specifies that tracking should use the ID of the selected variant rather than the ID of the parent * * #### Default Value * * `false` */ trackUsingVariant?: boolean; }; /** * Specifies the minimum window widths that correspond to each breakpoint. This is used determine when certain content items are displayed. * * #### Default Value * ```js * { * mobile: undefined, * tablet: 740, * desktop: 990 * } * ``` */ breakpoints?: Breakpoints; /** * Specifies component-specific configuration options */ components?: HawkSearchComponents; /** * Specifies which styles should be loaded for each component */ css?: { /** * One or more style sets to be loaded. This can be either a URL to an external stylesheet, the ID of a `template` element wrapping around a `style` element, or a string containing CSS rules. */ customStyles?: string | Array; /** * Specifies whether the default stylesheet should be loaded. This should generally be true except for with completely custom interfaces. */ defaultStyles?: boolean; }; /** * Specifies how values should be formatted for different cultures */ formatting?: { /** * #### Default Value * `'en-US'` */ cultureIsoCode?: string; /** * #### Default Value * `'USD'` */ currencyIsoCode?: string; }; /** * The URL of an image to be loaded whenever an image fails to load for a search result item */ placeholderImageUrl?: string; seo?: { title?: { /** * Value prepended to title returned from API */ prefix?: string; /** * Value appended to title returned from API */ suffix?: string; }; }; /** * Specifies whether components should be rendered in the [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM). This is highly recommended to avoid CSS conflicts. * * #### Default Value * `true` */ shadowDom?: boolean; /** * Specifies whether components should be rendered with custom style */ useCustomStyle?: boolean; /** * If your data contains relative URLs, these values can be prepended to the values to convert them to absolute URLs */ urlPrefixes?: { assets?: string; content?: string; }; /** * Specifies whether search queries should be displayed on console * * #### Default Value * `false` */ debug?: boolean; } export interface HawkSearchGlobal { config: HawkSearchConfig; handlebars: typeof Handlebars; recommendationsResponses?: { [widgetId: string]: RecommendationsResponse; }; /** @internal */ rawSearchRequest?: RawSearchRequest; searchRequest?: SearchRequest; searchResponse?: SearchResponse; services: { autocomplete: AutocompleteService; conversational: ConversationalService; recommendations: RecommendationsService; search: SearchService; tracking: TrackingService; }; init: (config: HawkSearchConfig) => void; } export interface HawkSearchState { searchRequest?: SearchRequest; searchResponse: SearchResponse; } export interface NoResultsComponentConfig extends BaseComponentConfig { strings?: { message?: string; suggestion?: string; query?: string; }; }