UNPKG

angular-instantsearch

Version:

Lightning-fast search for Angular apps, by Algolia.

2,956 lines 96.5 kB
import { Input, EventEmitter, isDevMode, VERSION as VERSION$1, Component, Inject, PLATFORM_ID, Output, SkipSelf, forwardRef, Optional, NgModule, ChangeDetectionStrategy, ContentChild, TemplateRef, ViewChild, KeyValueDiffers, NgZone } from '@angular/core';
import { isPlatformBrowser, CommonModule, DOCUMENT } from '@angular/common';
import { connectBreadcrumb, connectClearRefinements, connectCurrentRefinements, connectHierarchicalMenu, connectHitsPerPage, connectHitsWithInsights, connectInfiniteHitsWithInsights, connectMenu, connectNumericMenu, connectPagination, connectRange, connectRefinementList, connectSearchBox, connectSortBy, connectRatingMenu, connectStats, connectToggleRefinement, connectConfigure, EXPERIMENTAL_connectConfigureRelatedItems, connectQueryRules, connectVoiceSearch } from 'instantsearch.js/es/connectors';
import * as algoliasearchProxy from 'algoliasearch/lite';
import instantsearch from 'instantsearch.js/es';
import indexWidget from 'instantsearch.js/es/widgets/index/index';
import { highlight, reverseHighlight, snippet, reverseSnippet } from 'instantsearch.js/es/helpers';
import { getPropertyByPath as getPropertyByPath$1 } from 'instantsearch.js/es/lib/utils';
import * as noUiSlider from 'nouislider';
import * as encodeProxy from 'querystring-es3/encode';

function bem(widgetName) {
    const cx = function (element, subElement) {
        let cssClass = `ais-${widgetName}`;
        if (element) {
            cssClass += `-${element}`;
        }
        if (subElement) {
            cssClass += `--${subElement}`;
        }
        return cssClass;
    };
    return cx;
}
function parseNumberInput(input) {
    return typeof input === 'string' ? parseInt(input, 10) : input;
}
function noop(...args) { }
function capitalize(s) {
    return s.charAt(0).toUpperCase() + s.slice(1);
}
// See https://github.com/algolia/instantsearch.js/blob/9296022fecadfbf82f15e837c215a1356eac4bc5/src/lib/utils/range.ts
function range({ start = 0, end, step = 1, }) {
    // We can't divide by 0 so we re-assign the step to 1 if it happens.
    const limitStep = step === 0 ? 1 : step;
    // In some cases the array to create has a decimal length.
    // We therefore need to round the value.
    // Example:
    //   { start: 1, end: 5000, step: 500 }
    //   => Array length = (5000 - 1) / 500 = 9.998
    const arrayLength = Math.round((end - start) / limitStep);
    return [...Array(arrayLength)].map((_, current) => start + current * limitStep);
}
// See https://github.com/algolia/react-instantsearch/blob/86dfe8674d566124af55a8f044051d0062786c1a/packages/react-instantsearch-core/src/core/utils.ts#L138-L142
function getPropertyByPath(object, path) {
    return path
        .replace(/\[(\d+)]/g, '.$1')
        .split('.')
        .reduce((current, key) => (current ? current[key] : undefined), object);
}

class TypedBaseWidget {
    constructor(widgetName) {
        this.updateState = (state, isFirstRendering) => {
            if (isFirstRendering) {
                Promise.resolve().then(() => {
                    this.state = state;
                });
            }
            else {
                this.state = state;
            }
        };
        this.cx = bem(widgetName);
    }
    get parent() {
        if (this.parentIndex) {
            return this.parentIndex;
        }
        return this.instantSearchInstance;
    }
    createWidget(connector, options, additionalWidgetProperties = {}) {
        this.widget = Object.assign(Object.assign({}, connector(this.updateState, noop)(options)), additionalWidgetProperties);
    }
    ngOnInit() {
        this.parent.addWidgets([this.widget]);
    }
    ngOnDestroy() {
        if (isPlatformBrowser(this.instantSearchInstance.platformId)) {
            this.parent.removeWidgets([this.widget]);
        }
    }
    /**
     * Helper to generate class names for an item
     * @param item element to generate a class name for
     */
    getItemClass(item) {
        const className = this.cx('item');
        if (item.isRefined) {
            return `${className} ${this.cx('item', 'selected')}`;
        }
        return className;
    }
}
TypedBaseWidget.propDecorators = {
    autoHideContainer: [{ type: Input }]
};

const VERSION = '4.4.3';

// this is needed for different webpack/typescript configurations
const algoliasearch$1 = algoliasearchProxy.default || algoliasearchProxy;
class NgAisInstantSearch {
    constructor(platformId) {
        this.platformId = platformId;
        this.instanceName = 'default';
        this.change = new EventEmitter();
        this.onRender = () => {
            this.change.emit({
                results: this.instantSearchInstance.helper.lastResults,
                state: this.instantSearchInstance.helper.state,
            });
        };
    }
    ngOnInit() {
        if (isDevMode()) {
            console.warn(`We are deprecating Angular InstantSearch.
For more information and alternative solutions, go to https://alg.li/angular-deprecation.`);
        }
        if (typeof this.config.searchClient.addAlgoliaAgent === 'function') {
            this.config.searchClient.addAlgoliaAgent(`angular (${VERSION$1.full})`);
            this.config.searchClient.addAlgoliaAgent(`angular-instantsearch (${VERSION})`);
        }
        this.instantSearchInstance = instantsearch(this.config);
        this.instantSearchInstance.on('render', this.onRender);
    }
    ngAfterViewInit() {
        this.instantSearchInstance.start();
    }
    ngOnDestroy() {
        if (this.instantSearchInstance) {
            this.instantSearchInstance.removeListener('render', this.onRender);
            this.instantSearchInstance.dispose();
        }
    }
    addWidgets(widgets) {
        this.instantSearchInstance.addWidgets(widgets);
    }
    removeWidgets(widgets) {
        this.instantSearchInstance.removeWidgets(widgets);
    }
    refresh() {
        this.instantSearchInstance.refresh();
    }
}
NgAisInstantSearch.decorators = [
    { type: Component, args: [{
                selector: 'ais-instantsearch',
                template: '<ng-content></ng-content>'
            },] }
];
NgAisInstantSearch.ctorParameters = () => [
    { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }
];
NgAisInstantSearch.propDecorators = {
    config: [{ type: Input }],
    instanceName: [{ type: Input }],
    change: [{ type: Output }]
};

class NgAisIndex {
    constructor(
    // public API does not include SkipSelf, but the index widget should accept parents, avoiding itself.
    parentIndex, instantSearchInstance) {
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
    }
    get parent() {
        if (this.parentIndex) {
            return this.parentIndex;
        }
        return this.instantSearchInstance;
    }
    createWidget() {
        this.widget = Object.assign(Object.assign({}, indexWidget({
            indexName: this.indexName,
            indexId: this.indexId,
        })), { $$widgetType: 'ais.index' });
    }
    addWidgets(widgets) {
        this.widget.addWidgets(widgets);
    }
    removeWidgets(widgets) {
        this.widget.removeWidgets(widgets);
    }
    ngOnInit() {
        this.createWidget();
        this.parent.addWidgets([this.widget]);
    }
    ngOnDestroy() {
        if (isPlatformBrowser(this.instantSearchInstance.platformId)) {
            this.parent.removeWidgets([this.widget]);
        }
    }
}
NgAisIndex.decorators = [
    { type: Component, args: [{
                selector: 'ais-index',
                template: `<ng-content></ng-content>`
            },] }
];
NgAisIndex.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: SkipSelf }, { type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisIndex.propDecorators = {
    indexName: [{ type: Input }],
    indexId: [{ type: Input }]
};

class NgAisBreadcrumb extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('Breadcrumb');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            createURL: () => '#',
            items: [],
            refine: noop,
            canRefine: false,
        };
    }
    get isHidden() {
        return this.state.items.length === 0 && this.autoHideContainer;
    }
    get items() {
        return this.state.items.map((item, idx) => (Object.assign(Object.assign({}, item), { separator: idx !== 0, isLast: idx === this.state.items.length - 1 })));
    }
    ngOnInit() {
        this.createWidget(connectBreadcrumb, {
            attributes: this.attributes,
            rootPath: this.rootPath,
            separator: this.separator,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.breadcrumb',
        });
        super.ngOnInit();
    }
    handleClick(event, item) {
        event.preventDefault();
        event.stopPropagation();
        if (item.value) {
            this.state.refine(item.value);
        }
    }
}
NgAisBreadcrumb.decorators = [
    { type: Component, args: [{
                selector: 'ais-breadcrumb',
                template: `
    <div
      [class]="cx()"
      *ngIf="!isHidden"
    >
      <ul [class]="cx('list')">
        <li
          *ngFor="let item of items"
          [ngClass]="[cx('item'), item.isLast ? cx('item', 'selected') : '']"
          (click)="handleClick($event, item)"
        >
          <span
            *ngIf="item.separator"
            [class]="cx('separator')"
            aria-hidden="true"
          >
            >
          </span>
          <a
            [class]="cx('link')"
            href="{{state.createURL(item.value)}}"
            *ngIf="!item.isLast"
            (click)="handleClick($event, item)"
          >
            {{item.label}}
          </a>

          <span *ngIf="item.isLast">
            {{item.label}}
          </span>
        </li>
      </ul>
    </div>
  `
            },] }
];
NgAisBreadcrumb.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisBreadcrumb.propDecorators = {
    attributes: [{ type: Input }],
    rootPath: [{ type: Input }],
    separator: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisBreadcrumbModule {
}
NgAisBreadcrumbModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisBreadcrumb],
                entryComponents: [NgAisBreadcrumb],
                exports: [NgAisBreadcrumb],
                imports: [CommonModule],
            },] }
];

class NgAisClearRefinements extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('ClearRefinements');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        // rendering options
        this.resetLabel = 'Clear refinements';
        this.state = {
            hasRefinements: false,
            canRefine: false,
            refine: noop,
            createURL: () => '#',
        };
    }
    get isHidden() {
        return !this.state.hasRefinements && this.autoHideContainer;
    }
    ngOnInit() {
        this.createWidget(connectClearRefinements, {
            includedAttributes: this.includedAttributes,
            excludedAttributes: this.excludedAttributes,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.clearRefinements',
        });
        super.ngOnInit();
    }
    handleClick(event) {
        event.preventDefault();
        if (this.state.hasRefinements) {
            this.state.refine();
        }
    }
}
NgAisClearRefinements.decorators = [
    { type: Component, args: [{
                selector: 'ais-clear-refinements',
                template: `
    <div
      [class]="cx()"
      *ngIf="!isHidden"
    >
      <button
        [class]="cx('button') + (!state.hasRefinements ? (' ' + cx('button', 'disabled')) : '')"
        (click)="handleClick($event)"
        [disabled]="!state.hasRefinements"
      >
        {{resetLabel}}
      </button>
    </div>
  `
            },] }
];
NgAisClearRefinements.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisClearRefinements.propDecorators = {
    resetLabel: [{ type: Input }],
    includedAttributes: [{ type: Input }],
    excludedAttributes: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisClearRefinementsModule {
}
NgAisClearRefinementsModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisClearRefinements],
                entryComponents: [NgAisClearRefinements],
                exports: [NgAisClearRefinements],
                imports: [CommonModule],
            },] }
];

class NgAisCurrentRefinements extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('CurrentRefinements');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            createURL: () => '#',
            refine: noop,
            items: [],
            canRefine: false,
        };
    }
    get isHidden() {
        return this.state.items.length === 0 && this.autoHideContainer;
    }
    ngOnInit() {
        this.createWidget(connectCurrentRefinements, {
            includedAttributes: this.includedAttributes,
            excludedAttributes: this.excludedAttributes,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.currentRefinements',
        });
        super.ngOnInit();
    }
    handleClick(event, refinement) {
        event.preventDefault();
        this.state.refine(refinement);
    }
}
NgAisCurrentRefinements.decorators = [
    { type: Component, args: [{
                selector: 'ais-current-refinements',
                template: `
    <div
      [class]="cx()"
      *ngIf="!isHidden"
    >
      <ul
        [class]="cx('list')"
        *ngFor="let item of state.items"
      >
        <li [class]="cx('item')">
          <span [class]="cx('label')">{{item.label | titlecase}}:</span>

          <span
            [class]="cx('category')"
            *ngFor="let refinement of item.refinements"
          >
            <span [class]="cx('categoryLabel')">{{refinement.label}}</span>
            <button [class]="cx('delete')" (click)="handleClick($event, refinement)">✕</button>
          </span>
        </li>
      </ul>
    </div>
  `
            },] }
];
NgAisCurrentRefinements.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisCurrentRefinements.propDecorators = {
    includedAttributes: [{ type: Input }],
    excludedAttributes: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisCurrentRefinementsModule {
}
NgAisCurrentRefinementsModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisCurrentRefinements],
                entryComponents: [NgAisCurrentRefinements],
                exports: [NgAisCurrentRefinements],
                imports: [CommonModule],
            },] }
];

class NgAisHierarchicalMenu extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('HierarchicalMenu');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            createURL: () => '#',
            items: [],
            refine: noop,
            canRefine: false,
            isShowingMore: false,
            toggleShowMore: noop,
            canToggleShowMore: false,
            sendEvent: noop,
        };
    }
    get isHidden() {
        return this.state.items.length === 0 && this.autoHideContainer;
    }
    ngOnInit() {
        this.createWidget(connectHierarchicalMenu, {
            limit: parseNumberInput(this.limit),
            attributes: this.attributes,
            rootPath: this.rootPath,
            separator: this.separator,
            showParentLevel: this.showParentLevel,
            sortBy: this.sortBy,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.hierarchicalMenu',
        });
        super.ngOnInit();
    }
}
NgAisHierarchicalMenu.decorators = [
    { type: Component, args: [{
                selector: 'ais-hierarchical-menu',
                template: `
    <div
      [class]="cx()"
      *ngIf="!isHidden"
    >
      <ul [class]="cx('list') + ' ' + cx('list', 'lvl0')">
        <ais-hierarchical-menu-item
          *ngFor="let item of state.items"
          [item]="item"
          [createURL]="state.createURL"
          [refine]="state.refine"
        >
        </ais-hierarchical-menu-item>
      </ul>
    </div>
  `
            },] }
];
NgAisHierarchicalMenu.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisHierarchicalMenu.propDecorators = {
    attributes: [{ type: Input }],
    separator: [{ type: Input }],
    rootPath: [{ type: Input }],
    showParentLevel: [{ type: Input }],
    limit: [{ type: Input }],
    sortBy: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisHierarchicalMenuItem {
    constructor() {
        this.lvl = 1;
        this.cx = bem('HierarchicalMenu');
    }
    getItemClass(item) {
        let className = this.cx('item');
        if (item.isRefined) {
            className = `${className} ${this.cx('item', 'selected')}`;
        }
        if (this.isArray(item.data) && item.data.length > 0) {
            className = `${className} ${this.cx('item', 'parent')}`;
        }
        return className;
    }
    getListClass() {
        return `${this.cx('list')} ${this.cx('list', 'child')} ${this.cx('list', `lvl${this.lvl}`)}`;
    }
    isArray(potentialArray) {
        return Array.isArray(potentialArray);
    }
    handleClick(event, item) {
        event.preventDefault();
        event.stopPropagation();
        this.refine(item.value);
    }
}
NgAisHierarchicalMenuItem.decorators = [
    { type: Component, args: [{
                selector: 'ais-hierarchical-menu-item',
                template: `
    <li
      [class]="getItemClass(item)"
      (click)="handleClick($event, item)"
    >
      <a
        [class]="cx('link')"
        href="{{createURL(item.value)}}"
        (click)="handleClick($event, item)"
      >
        <span [class]="cx('label')">{{item.label}}</span>
        <span [class]="cx('count')">{{item.count}}</span>
      </a>

      <ul
        [class]="getListClass()"
        *ngIf="item.isRefined && isArray(item.data) && item.data.length > 0"
      >
        <ais-hierarchical-menu-item
          *ngFor="let child of item.data"
          [item]="child"
          [createURL]="createURL"
          [refine]="refine"
          [lvl]="lvl + 1"
        >
        </ais-hierarchical-menu-item>
      </ul>
    </li>
  `
            },] }
];
NgAisHierarchicalMenuItem.propDecorators = {
    lvl: [{ type: Input }],
    refine: [{ type: Input }],
    createURL: [{ type: Input }],
    item: [{ type: Input }]
};

class NgAisHierarchicalMenuModule {
}
NgAisHierarchicalMenuModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisHierarchicalMenu, NgAisHierarchicalMenuItem],
                entryComponents: [NgAisHierarchicalMenu],
                exports: [NgAisHierarchicalMenu],
                imports: [CommonModule],
            },] }
];

class NgAisHitsPerPage extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('HitsPerPage');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            items: [],
            refine: noop,
            hasNoResults: true,
            canRefine: false,
        };
    }
    get isHidden() {
        return this.state.items.length === 0 && this.autoHideContainer;
    }
    ngOnInit() {
        this.createWidget(connectHitsPerPage, {
            items: this.items,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.hitsPerPage',
        });
        super.ngOnInit();
    }
}
NgAisHitsPerPage.decorators = [
    { type: Component, args: [{
                selector: 'ais-hits-per-page',
                template: `
    <div
      [class]="cx()"
      *ngIf="!isHidden"
    >
      <select
        [class]="cx('select')"
        (change)="state.refine($event.target.value)"
      >
        <option
          [class]="cx('option')"
          *ngFor="let item of state.items"
          [value]="item.value"
          [selected]="item.isRefined"
        >
          {{item.label}}
        </option>
      </select>
    </div>
  `
            },] }
];
NgAisHitsPerPage.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisHitsPerPage.propDecorators = {
    items: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisHitsPerPageModule {
}
NgAisHitsPerPageModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisHitsPerPage],
                entryComponents: [NgAisHitsPerPage],
                exports: [NgAisHitsPerPage],
                imports: [CommonModule],
            },] }
];

class NgAisHighlight {
    constructor() {
        this.tagName = 'mark';
    }
    get content() {
        const highlightAttributeResult = getPropertyByPath$1(this.hit._highlightResult, this.attribute);
        const fallback = getPropertyByPath$1(this.hit, this.attribute);
        // @MAJOR drop this custom fallback once it is implemented directly in instantsearch.js v5
        if (!highlightAttributeResult && fallback) {
            return fallback;
        }
        return highlight({
            attribute: this.attribute,
            highlightedTagName: this.tagName,
            hit: this.hit,
        });
    }
}
NgAisHighlight.decorators = [
    { type: Component, args: [{
                selector: 'ais-highlight',
                changeDetection: ChangeDetectionStrategy.OnPush,
                template: `<span class="ais-Highlight" [innerHtml]="content"></span>`
            },] }
];
NgAisHighlight.propDecorators = {
    attribute: [{ type: Input }],
    hit: [{ type: Input }],
    tagName: [{ type: Input }]
};

class NgAisHighlightModule {
}
NgAisHighlightModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisHighlight],
                entryComponents: [NgAisHighlight],
                exports: [NgAisHighlight],
                imports: [CommonModule],
            },] }
];

class NgAisHits extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('Hits');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            hits: [],
            results: undefined,
            bindEvent: undefined,
            sendEvent: undefined,
        };
        this.updateState = (state, isFirstRendering) => {
            if (isFirstRendering)
                return;
            this.state = state;
        };
    }
    ngOnInit() {
        this.createWidget(connectHitsWithInsights, {
            escapeHTML: this.escapeHTML,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.hits',
        });
        super.ngOnInit();
    }
}
NgAisHits.decorators = [
    { type: Component, args: [{
                selector: 'ais-hits',
                template: `
    <div [class]="cx()">
      <ng-container *ngTemplateOutlet="template; context: state"></ng-container>

      <!-- default rendering if no template specified -->
      <div *ngIf="!template">
        <ul [class]="cx('list')">
          <li
            [class]="cx('item')"
            *ngFor="let hit of state.hits"
          >
            <ais-highlight attribute="name" [hit]="hit">
            </ais-highlight>
          </li>
        </ul>
      </div>
    </div>
  `
            },] }
];
NgAisHits.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisHits.propDecorators = {
    template: [{ type: ContentChild, args: [TemplateRef, { static: false },] }],
    escapeHTML: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisHitsModule {
}
NgAisHitsModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisHits],
                entryComponents: [NgAisHits],
                exports: [NgAisHits],
                imports: [CommonModule, NgAisHighlightModule],
            },] }
];

class NgAisIndexModule {
    static forRoot() {
        return {
            ngModule: NgAisIndexModule,
            providers: [],
        };
    }
}
NgAisIndexModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisIndex],
                entryComponents: [NgAisIndex],
                exports: [NgAisIndex],
                imports: [CommonModule],
            },] }
];

class NgAisInfiniteHits extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('InfiniteHits');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.showPrevious = false;
        this.showPreviousLabel = 'Show previous results';
        this.showMoreLabel = 'Show more results';
        this.state = {
            hits: [],
            results: undefined,
            currentPageHits: [],
            isFirstPage: false,
            isLastPage: false,
            showMore: noop,
            showPrevious: noop,
            sendEvent: noop,
            bindEvent: () => '',
        };
        this.updateState = (state, isFirstRendering) => {
            if (isFirstRendering)
                return;
            this.state = state;
        };
    }
    ngOnInit() {
        this.createWidget(connectInfiniteHitsWithInsights, {
            escapeHTML: this.escapeHTML,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.infiniteHits',
        });
        super.ngOnInit();
    }
    showMoreHandler(event) {
        event.preventDefault();
        this.state.showMore();
    }
    showPreviousHandler(event) {
        event.preventDefault();
        this.state.showPrevious();
    }
}
NgAisInfiniteHits.decorators = [
    { type: Component, args: [{
                selector: 'ais-infinite-hits',
                template: `
    <div [class]="cx()">
      <ng-container *ngTemplateOutlet="template; context: state"></ng-container>

      <!-- default rendering if no template specified -->
      <button
        [ngClass]="[cx('loadPrevious'), this.state.isFirstPage ? cx('loadPrevious', 'disabled') : '']"
        (click)="showPreviousHandler($event)"
        [disabled]="state.isFirstPage"
        *ngIf="showPrevious && !template"
      >
        {{showPreviousLabel}}
      </button>

      <div *ngIf="!template">
        <ul [class]="cx('list')">
          <li
            [class]="cx('item')"
            *ngFor="let hit of state.hits"
          >
            <ais-highlight attribute="name" [hit]="hit">
            </ais-highlight>
          </li>
        </ul>
      </div>

      <button
        [ngClass]="[cx('loadMore'), this.state.isLastPage ? cx('loadMore', 'disabled') : '']"
        (click)="showMoreHandler($event)"
        [disabled]="state.isLastPage"
        *ngIf="!template"
      >
        {{showMoreLabel}}
      </button>
    </div>
  `
            },] }
];
NgAisInfiniteHits.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisInfiniteHits.propDecorators = {
    template: [{ type: ContentChild, args: [TemplateRef, { static: false },] }],
    escapeHTML: [{ type: Input }],
    showPrevious: [{ type: Input }],
    showPreviousLabel: [{ type: Input }],
    showMoreLabel: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisInfiniteHitsModule {
}
NgAisInfiniteHitsModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisInfiniteHits],
                entryComponents: [NgAisInfiniteHits],
                exports: [NgAisInfiniteHits],
                imports: [CommonModule, NgAisHighlightModule],
            },] }
];

class NgAisInstantSearchModule {
    static forRoot() {
        return {
            ngModule: NgAisInstantSearchModule,
            providers: [],
        };
    }
}
NgAisInstantSearchModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisInstantSearch],
                entryComponents: [NgAisInstantSearch],
                exports: [NgAisInstantSearch],
                imports: [CommonModule],
            },] }
];

class NgAisMenu extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('Menu');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        // rendering options
        this.showMoreLabel = 'Show more';
        this.showLessLabel = 'Show less';
        this.state = {
            items: [],
            refine: noop,
            createURL: () => '#',
            canRefine: false,
            isShowingMore: false,
            canToggleShowMore: false,
            toggleShowMore: noop,
            sendEvent: noop,
        };
    }
    get isHidden() {
        return this.state.items.length === 0 && this.autoHideContainer;
    }
    get showMoreClass() {
        let className = this.cx('showMore');
        if (!this.state.canToggleShowMore) {
            className = `${className} ${this.cx('showMore', 'disabled')}`;
        }
        return className;
    }
    ngOnInit() {
        this.createWidget(connectMenu, {
            attribute: this.attribute,
            showMore: this.showMore,
            limit: this.limit,
            showMoreLimit: this.showMoreLimit,
            sortBy: this.sortBy,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.menu',
        });
        super.ngOnInit();
    }
    handleClick(event, value) {
        event.preventDefault();
        event.stopPropagation();
        this.state.refine(value);
    }
}
NgAisMenu.decorators = [
    { type: Component, args: [{
                selector: 'ais-menu',
                template: `
    <div
      [class]="cx()"
      *ngIf="!isHidden"
    >
      <ul [class]="cx('list')">
        <li
          [class]="getItemClass(item)"
          *ngFor="let item of state.items"
          (click)="handleClick($event, item.value)"
        >
          <a
            href="{{state.createURL(item.value)}}"
            [class]="cx('link')"
            (click)="handleClick($event, item.value)"
          >
            <span [class]="cx('label')">{{item.label}}</span>
            <span [class]="cx('count')">{{item.count}}</span>
          </a>
        </li>
      </ul>

      <button
        *ngIf="showMore"
        (click)="state.toggleShowMore()"
        [class]="showMoreClass"
        [disabled]="!state.canToggleShowMore"
      >
        {{state.isShowingMore ? showLessLabel : showMoreLabel}}
      </button>
    </div>
  `
            },] }
];
NgAisMenu.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisMenu.propDecorators = {
    showMoreLabel: [{ type: Input }],
    showLessLabel: [{ type: Input }],
    attribute: [{ type: Input }],
    showMore: [{ type: Input }],
    limit: [{ type: Input }],
    showMoreLimit: [{ type: Input }],
    sortBy: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisMenuModule {
}
NgAisMenuModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisMenu],
                entryComponents: [NgAisMenu],
                exports: [NgAisMenu],
                imports: [CommonModule],
            },] }
];

class NgAisNumericMenu extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('NumericMenu');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            items: [],
            refine: noop,
            createURL: () => '#',
            hasNoResults: true,
            sendEvent: noop,
            canRefine: false,
        };
    }
    get isHidden() {
        return this.state.items.length === 0 && this.autoHideContainer;
    }
    ngOnInit() {
        this.createWidget(connectNumericMenu, {
            attribute: this.attribute,
            items: this.items,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.numericMenu',
        });
        super.ngOnInit();
    }
    refine(event, item) {
        event.preventDefault();
        event.stopPropagation();
        this.state.refine(item.value);
    }
}
NgAisNumericMenu.decorators = [
    { type: Component, args: [{
                selector: 'ais-numeric-menu',
                template: `
    <div
      [class]="cx()"
      *ngIf="!isHidden"
    >
      <ul [class]="cx('list')">
        <li
          [class]="getItemClass(item)"
          *ngFor="let item of state.items"
        >
          <label [class]="cx('label')">
            <input
              [class]="cx('radio')"
              type="radio"
              name="NumericMenu"
              [checked]="item.isRefined"
              (change)="refine($event, item)"
            />
            <span [class]="cx('labelText')">{{item.label}}</span>
          </label>
        </li>
      </ul>
    </div>
  `
            },] }
];
NgAisNumericMenu.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisNumericMenu.propDecorators = {
    attribute: [{ type: Input }],
    items: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisNumericMenuModule {
}
NgAisNumericMenuModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisNumericMenu],
                entryComponents: [NgAisNumericMenu],
                exports: [NgAisNumericMenu],
                imports: [CommonModule],
            },] }
];

class NgAisPagination extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('Pagination');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        // rendering options
        this.showFirst = true;
        this.showLast = true;
        this.showPrevious = true;
        this.showNext = true;
        // TODO: check if this works, padding and totalPages are most likely strings when passed to the template
        this.state = {
            createURL: () => '#',
            currentRefinement: 0,
            nbHits: 0,
            nbPages: 0,
            refine: noop,
            pages: [],
            canRefine: false,
            isFirstPage: false,
            isLastPage: false,
        };
    }
    ngOnInit() {
        this.createWidget(connectPagination, {
            padding: parseNumberInput(this.padding),
            totalPages: parseNumberInput(this.totalPages),
        }, {
            $$widgetType: 'ais.pagination',
        });
        super.ngOnInit();
    }
    refine(event, page) {
        event.stopPropagation();
        event.preventDefault();
        if (page < 0 ||
            page === this.state.currentRefinement ||
            page >= this.state.nbPages) {
            return;
        }
        this.state.refine(page);
    }
}
NgAisPagination.decorators = [
    { type: Component, args: [{
                selector: 'ais-pagination',
                template: `
    <div [ngClass]="[cx(), state.nbPages <= 1 ? cx('', 'noRefinement') : '']">
      <ul [class]="cx('list')">
        <li
          *ngIf="showFirst"
          (click)="refine($event, 0)"
          [class]="
            cx('item') +
            ' ' +
            cx('item', 'firstPage') +
            (state.currentRefinement === 0 ? ' ' + cx('item', 'disabled') : '')
          "
        >
          <a
            [href]="state.createURL(0)"
            [class]="cx('link')"
          >
            ‹‹
          </a>
        </li>

        <li
          *ngIf="showPrevious"
          (click)="refine($event, state.currentRefinement - 1)"
          [class]="
            cx('item') +
            ' ' +
            cx('item', 'previousPage') +
            (state.currentRefinement === 0 ? ' ' + cx('item', 'disabled') : '')
          "
        >
          <a
            [href]="state.createURL(state.currentRefinement - 1)"
            [class]="cx('link')"
          >
            ‹
          </a>
        </li>

        <li
          [class]="
            cx('item') +
            ' ' +
            cx('item', 'page') +
            (state.currentRefinement === page ? ' ' + cx('item', 'selected') : '')
          "
          *ngFor="let page of state.pages"
          (click)="refine($event, page)"
        >
          <a
            [class]="cx('link')"
            [href]="state.createURL(page)"
          >
            {{page + 1}}
          </a>
        </li>

        <li
          *ngIf="showNext"
          (click)="refine($event, state.currentRefinement + 1)"
          [class]="
            cx('item') +
            ' ' +
            cx('item', 'nextPage') +
            (state.currentRefinement + 1 === state.nbPages ? ' ' + cx('item', 'disabled') : '')
          "
        >
          <a
            [href]="state.createURL(state.currentRefinement + 1)"
            [class]="cx('link')"
          >
            ›
          </a>
        </li>

        <li
          *ngIf="showLast"
          (click)="refine($event, state.nbPages - 1)"
          [class]="
            cx('item') +
            ' ' +
            cx('item', 'lastPage') +
            (state.currentRefinement + 1 === state.nbPages ? ' ' + cx('item', 'disabled') : '')
          "
        >
          <a
            [href]="state.createURL(state.nbPages - 1)"
            [class]="cx('link')"
          >
            ››
          </a>
        </li>
      </ul>
    </div>
  `
            },] }
];
NgAisPagination.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisPagination.propDecorators = {
    showFirst: [{ type: Input }],
    showLast: [{ type: Input }],
    showPrevious: [{ type: Input }],
    showNext: [{ type: Input }],
    padding: [{ type: Input }],
    totalPages: [{ type: Input }]
};

class NgAisPaginationModule {
}
NgAisPaginationModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisPagination],
                entryComponents: [NgAisPagination],
                exports: [NgAisPagination],
                imports: [CommonModule],
            },] }
];

class NgAisRangeSlider extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('RangeSlider');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        // rendering options
        this.pips = true;
        this.tooltips = true;
        this.state = {
            canRefine: false,
            format: {
                from: () => '',
                to: () => '',
            },
            range: { min: 0, max: 1 },
            refine: noop,
            start: [0, 1],
            sendEvent: noop,
        };
        this.updateState = (state, isFirstRendering) => {
            if (isFirstRendering) {
                // create slider
                const config = {
                    animate: false,
                    behaviour: 'snap',
                    connect: true,
                    range: { min: 0, max: 1 },
                    start: [0, 1],
                    step: this.step,
                    tooltips: this.tooltips && [
                        { to: this.formatTooltip },
                        { to: this.formatTooltip },
                    ],
                };
                // tslint:disable-next-line: no-boolean-literal-compare (pips is @Input, so could be not a boolean)
                if (this.pips === true || typeof this.pips === 'undefined') {
                    Object.assign(config, {
                        pips: {
                            density: 3,
                            mode: 'positions',
                            stepped: true,
                            values: [0, 50, 100],
                        },
                    });
                }
                else if (this.pips !== undefined) {
                    Object.assign(config, { pips: this.pips });
                }
                this.slider = noUiSlider.create(this.sliderContainer.nativeElement, config);
                // register listen events
                this.sliderContainer.nativeElement.noUiSlider.on('change', this.handleChange);
            }
            // update component inner state
            this.state = state;
            // update the slider state
            const { range: { min, max }, start, } = state;
            const disabled = min === max;
            const range = disabled ? { min, max: max + 0.0001 } : { min, max };
            // TODO: test this as we're nolonger passing disable
            // it seems the API has changed: slider.setAttribute('disabled', true) / slider.removeAttribute('disabled');
            // see: https://refreshless.com/nouislider/more/#section-disable
            this.slider.updateOptions({ range, start });
        };
        this.handleChange = (values) => {
            this.state.refine(values);
        };
        this.formatTooltip = (value) => {
            return value.toFixed(parseNumberInput(this.precision));
        };
    }
    get step() {
        // compute step from the precision value
        const precision = parseNumberInput(this.precision) || 2;
        return 1 / Math.pow(10, precision);
    }
    ngOnInit() {
        this.createWidget(connectRange, {
            attribute: this.attribute,
            max: parseNumberInput(this.max),
            min: parseNumberInput(this.min),
            precision: parseNumberInput(this.precision),
        }, {
            $$widgetType: 'ais.rangeSlider',
        });
        super.ngOnInit();
    }
}
NgAisRangeSlider.decorators = [
    { type: Component, args: [{
                selector: 'ais-range-slider',
                template: `
    <div [class]="cx()">
      <div [class]="cx('body')">
        <div #sliderContainer></div>
      </div>
    </div>
  `
            },] }
];
NgAisRangeSlider.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisRangeSlider.propDecorators = {
    sliderContainer: [{ type: ViewChild, args: ['sliderContainer', { static: false },] }],
    pips: [{ type: Input }],
    tooltips: [{ type: Input }],
    attribute: [{ type: Input }],
    min: [{ type: Input }],
    max: [{ type: Input }],
    precision: [{ type: Input }]
};

class NgAisRangeSliderModule {
}
NgAisRangeSliderModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisRangeSlider],
                entryComponents: [NgAisRangeSlider],
                exports: [NgAisRangeSlider],
                imports: [CommonModule],
            },] }
];

class NgAisRefinementList extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('RefinementList');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        // rendering options
        this.showMoreLabel = 'Show more';
        this.showLessLabel = 'Show less';
        this.searchPlaceholder = 'Search here...';
        this.state = {
            canRefine: false,
            canToggleShowMore: false,
            createURL: () => '',
            isShowingMore: false,
            items: [],
            refine: noop,
            toggleShowMore: noop,
            searchForItems: noop,
            isFromSearch: false,
            hasExhaustiveItems: false,
            sendEvent: noop,
        };
    }
    get isHidden() {
        return this.state.items.length === 0 && this.autoHideContainer;
    }
    ngOnInit() {
        this.createWidget(connectRefinementList, {
            showMore: this.showMore,
            limit: parseNumberInput(this.limit),
            showMoreLimit: parseNumberInput(this.showMoreLimit),
            attribute: this.attribute,
            operator: this.operator,
            sortBy: this.sortBy,
            escapeFacetValues: true,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.refinementList',
        });
        super.ngOnInit();
    }
    refine(event, item) {
        event.preventDefault();
        event.stopPropagation();
        if (this.state.canRefine) {
            // update UI directly, it will update the checkbox state
            item.isRefined = !item.isRefined;
            // refine through Algolia API
            this.state.refine(item.value);
        }
    }
}
NgAisRefinementList.decorators = [
    { type: Component, args: [{
                selector: 'ais-refinement-list',
                template: `
    <div
      [class]="cx()"
      *ngIf="!isHidden"
    >
      <div
        *ngIf="searchable"
        [class]="cx('searchBox')"
      >
        <ais-facets-search
          [search]="state.searchForItems"
          [searchPlaceholder]="searchPlaceholder"
        >
        </ais-facets-search>
      </div>

      <ul [class]="cx('list')">
        <li
          [class]="getItemClass(item)"
          *ngFor="let item of state.items"
          (click)="refine($event, item)"
        >
          <label [class]="cx('label')">
            <input
              [class]="cx('checkbox')"
              type="checkbox"
              value="{{item.value}}"
              [checked]="item.isRefined"
            />
            <span [class]="cx('labelText')">
              <ais-highlight attribute="highlighted" [hit]="item"></ais-highlight>
            </span>
            <span [class]="cx('count')">{{item.count}}</span>
          </label>
        </li>
      </ul>

      <button
        [class]="cx('showMore')"
        *ngIf="showMore"
        (click)="state.toggleShowMore()"
        [disabled]="!state.canToggleShowMore"
      >
        {{state.isShowingMore ? showLessLabel : showMoreLabel}}
      </button>
    </div>
  `
            },] }
];
NgAisRefinementList.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisRefinementList.propDecorators = {
    showMoreLabel: [{ type: Input }],
    showLessLabel: [{ type: Input }],
    searchable: [{ type: Input }],
    searchPlaceholder: [{ type: Input }],
    attribute: [{ type: Input }],
    operator: [{ type: Input }],
    limit: [{ type: Input }],
    showMore: [{ type: Input }],
    showMoreLimit: [{ type: Input }],
    sortBy: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisFacetsSearch {
    constructor() {
        this.cx = bem('SearchBox');
        this.searchQuery = '';
    }
    handleChange(value) {
        this.searchQuery = value;
        this.search(value);
    }
    handleSubmit(event) {
        event.preventDefault();
        this.search(this.searchQuery);
    }
}
NgAisFacetsSearch.decorators = [
    { type: Component, args: [{
                selector: 'ais-facets-search',
                template: `
    <div [class]="cx()">
      <form
        [class]="cx('form')"
        (submit)="handleSubmit($event)"
        novalidate
      >
        <input
          [class]="cx('input')"
          autocapitalize="off"
          autocorrect="off"
          placeholder="{{searchPlaceholder}}"
          role="textbox"
          spellcheck="false"
          type="text"
          [value]="searchQuery"
          (input)="handleChange($event.target.value)"
        />

        <button
          [class]="cx('submit')"
          title="Submit the search query."
          type="submit"
        >
          <svg
            [ngClass]="cx('submitIcon')"
            viewBox="0 0 40 40"
            width="10"
            height="10"
          >
            <path d="M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z"></path>
          </svg>
        </button>

        <button
          [class]="cx('reset')"
          type="reset"
          title="Clear the search query."
          hidden
        >
          <svg
            [ngClass]="cx('resetIcon')"
            viewBox="0 0 20 20"
            width="10"
            height="10"
          >
            <path d="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"></path>
          </svg>
        </button>
      </form>
    </div>
  `
            },] }
];
NgAisFacetsSearch.propDecorators = {
    searchPlaceholder: [{ type: Input }],
    search: [{ type: Input }]
};

class NgAisRefinementListModule {
}
NgAisRefinementListModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisRefinementList, NgAisFacetsSearch],
                entryComponents: [NgAisRefinementList],
                exports: [NgAisRefinementList],
                imports: [CommonModule, NgAisHighlightModule],
            },] }
];

class NgAisSearchBox extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance, injectedDocument) {
        super('SearchBox');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.injectedDocument = injectedDocument;
        this.placeholder = 'Search';
        this.submitTitle = 'Submit';
        this.resetTitle = 'Reset';
        this.searchAsYouType = true;
        this.autofocus = false;
        this.showLoadingIndicator = true;
        // Output events
        // form
        this.submit = new EventEmitter();
        this.reset = new EventEmitter();
        // input
        this.change = new EventEmitter();
        this.focus = new EventEmitter();
        this.blur = new EventEmitter();
        this.query = '';
        this.state = {
            query: '',
            refine: noop,
            clear: noop,
            isSearchStalled: false,
        };
        this.createWidget(connectSearchBox, {}, {
            $$widgetType: 'ais.searchBox',
        });
        this.document = injectedDocument;
    }
    ngAfterViewInit() {
        if (this.autofocus) {
            this.searchBox.nativeElement.focus();
        }
    }
    ngDoCheck() {
        // We bypass the state update if the input is focused to avoid concurrent
        // updates when typing.
        if (this.query !== this.state.query &&
            this.searchBox &&
            this.searchBox.nativeElement &&
            this.document.activeElement !== this.searchBox.nativeElement) {
            this.query = this.state.query;
        }
    }
    handleChange(query) {
        this.change.emit(query);
        if (this.searchAsYouType) {
            this.state.refine(query);
        }
    }
    handleSubmit(event) {
        // send submit event to parent component
        this.submit.emit(event);
        event.preventDefault();
        if (!this.searchAsYouType) {
            this.state.refine(this.searchBox.nativeElement.value);
        }
    }
    handleReset(event) {
        // send reset event to parent component
        this.reset.emit(event);
        // reset search
        this.state.refine('');
    }
}
NgAisSearchBox.decorators = [
    { type: Component, args: [{
                selector: 'ais-search-box',
                template: `
    <div [class]="cx()">
      <form
        [class]="cx('form')"
        novalidate
        (submit)="handleSubmit($event)"
      >
        <input
          [class]="cx('input')"
          autocapitalize="off"
          autocorrect="off"
          placeholder="{{placeholder}}"
          role="textbox"
          spellcheck="false"
          type="text"
          [value]="query"
          (input)="handleChange($event.target.value)"
          (focus)="focus.emit($event)"
          (blur)="blur.emit($event)"
          #searchBox
        />

        <button
          [class]="cx('submit')"
          type="submit"
          title="{{submitTitle}}"
        >
          <svg
            [ngClass]="cx('submitIcon')"
            viewBox="0 0 40 40"
            width="40"
            height="40"
          >
            <path d="M26.804 29.01c-2.832 2.34-6.465 3.746-10.426 3.746C7.333 32.756 0 25.424 0 16.378 0 7.333 7.333 0 16.378 0c9.046 0 16.378 7.333 16.378 16.378 0 3.96-1.406 7.594-3.746 10.426l10.534 10.534c.607.607.61 1.59-.004 2.202-.61.61-1.597.61-2.202.004L26.804 29.01zm-10.426.627c7.323 0 13.26-5.936 13.26-13.26 0-7.32-5.937-13.257-13.26-13.257C9.056 3.12 3.12 9.056 3.12 16.378c0 7.323 5.936 13.26 13.258 13.26z"></path>
          </svg>
        </button>

        <button
          [class]="cx('reset')"
          type="reset"
          title="{{resetTitle}}"
          (click)="handleReset($event)"
          [hidden]="!state.query || (state.query && !state.query.trim()) || (state.isSearchStalled && showLoadingIndicator)">
          <svg
            [ngClass]="cx('resetIcon')"
            viewBox="0 0 20 20"
            width="20"
            height="20"
          >
            <path d="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"></path>
          </svg>
        </button>

        <span
          [class]="cx('loadingIndicator')"
          [hidden]="!showLoadingIndicator || !state.isSearchStalled"
        >
          <svg
            width="16"
            height="16"
            viewBox="0 0 38 38"
            stroke="#444"
            [ngClass]="cx('loadingIcon')"
          >
            <g fill="none" fillRule="evenodd">
              <g transform="translate(1 1)" strokeWidth="2">
                <circle strokeOpacity=".5" cx="18" cy="18" r="18" />
                <path d="M36 18c0-9.94-8.06-18-18-18">
                  <animateTransform
                    attributeName="transform"
                    type="rotate"
                    from="0 18 18"
                    to="360 18 18"
                    dur="1s"
                    repeatCount="indefinite"
                  />
                </path>
              </g>
            </g>
          </svg>
        </span>
      </form>
    </div>
  `
            },] }
];
NgAisSearchBox.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] },
    { type: Document, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
];
NgAisSearchBox.propDecorators = {
    searchBox: [{ type: ViewChild, args: ['searchBox', { static: false },] }],
    placeholder: [{ type: Input }],
    submitTitle: [{ type: Input }],
    resetTitle: [{ type: Input }],
    searchAsYouType: [{ type: Input }],
    autofocus: [{ type: Input }],
    showLoadingIndicator: [{ type: Input }],
    submit: [{ type: Output }],
    reset: [{ type: Output }],
    change: [{ type: Output }],
    focus: [{ type: Output }],
    blur: [{ type: Output }]
};

class NgAisSearchBoxModule {
}
NgAisSearchBoxModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisSearchBox],
                entryComponents: [NgAisSearchBox],
                exports: [NgAisSearchBox],
                imports: [CommonModule],
            },] }
];

class NgAisSortBy extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('SortBy');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            currentRefinement: null,
            options: [],
            refine: noop,
            hasNoResults: false,
            canRefine: false,
        };
    }
    ngOnInit() {
        this.createWidget(connectSortBy, {
            items: this.items,
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.sortBy',
        });
        super.ngOnInit();
    }
}
NgAisSortBy.decorators = [
    { type: Component, args: [{
                selector: 'ais-sort-by',
                template: `
    <div [class]="cx()">
      <select
        [class]="cx('select')"
        (change)="state.refine($event.target.value)"
      >
        <option
          [class]="cx('option')"
          *ngFor="let item of state.options"
          [value]="item.value"
          [selected]="item.value === state.currentRefinement"
        >
          {{item.label}}
        </option>
      </select>
    </div>
  `
            },] }
];
NgAisSortBy.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisSortBy.propDecorators = {
    items: [{ type: Input }],
    transformItems: [{ type: Input }]
};

class NgAisSortByModule {
}
NgAisSortByModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisSortBy],
                entryComponents: [NgAisSortBy],
                exports: [NgAisSortBy],
                imports: [CommonModule],
            },] }
];

class NgAisRatingMenu extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('RatingMenu');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        // rendering options
        this.andUpLabel = '& Up';
        this.state = {
            createURL: () => '#',
            hasNoResults: false,
            items: [],
            refine: noop,
            canRefine: false,
            sendEvent: noop,
        };
    }
    get isHidden() {
        return this.state.items.length === 0 && this.autoHideContainer;
    }
    ngOnInit() {
        this.createWidget(connectRatingMenu, {
            attribute: this.attribute,
            max: parseNumberInput(this.max),
        }, {
            $$widgetType: 'ais.ratingMenu',
        });
        super.ngOnInit();
    }
    handleClick(event, value) {
        event.preventDefault();
        event.stopPropagation();
        this.state.refine(value);
    }
}
NgAisRatingMenu.decorators = [
    { type: Component, args: [{
                selector: 'ais-rating-menu',
                template: `
    <div
      [ngClass]="[
        cx(),
        state.items.length === 0 ? cx('', 'noRefinement') : ''
      ]"
      *ngIf="!isHidden"
    >
      <svg style="display:none;">
        <symbol
          id="ais-StarRating-starSymbol"
          viewBox="0 0 24 24"
        >
          <path d="M12 .288l2.833 8.718h9.167l-7.417 5.389 2.833 8.718-7.416-5.388-7.417 5.388 2.833-8.718-7.416-5.389h9.167z"/>
        </symbol>
        <symbol
          id="ais-StarRating-starEmptySymbol"
          viewBox="0 0 24 24"
        >
          <path d="M12 6.76l1.379 4.246h4.465l-3.612 2.625 1.379 4.246-3.611-2.625-3.612 2.625 1.379-4.246-3.612-2.625h4.465l1.38-4.246zm0-6.472l-2.833 8.718h-9.167l7.416 5.389-2.833 8.718 7.417-5.388 7.416 5.388-2.833-8.718 7.417-5.389h-9.167l-2.833-8.718z"/>
        </symbol>
      </svg>

      <ul [class]="cx('list')">
        <li
          *ngFor="let item of state.items"
          [class]="getItemClass(item)"
          (click)="handleClick($event, item.value)"
        >
          <a
            href="{{state.createURL(item.value)}}"
            [class]="cx('link')"
            (click)="handleClick($event, item.value)"
          >
            <svg
              width="24"
              height="24"
              *ngFor="let star of item.stars"
              [ngClass]="cx('starIcon') + ' ' + (star ? cx('starIcon', 'full') : cx('starIcon', 'empty'))"
              aria-hidden="true"
            >
              <use
                *ngIf="star"
                xlink:href="#ais-StarRating-starSymbol"
              >
              </use>

              <use
                *ngIf="!star"
                xlink:href="#ais-StarRating-starEmptySymbol"
              >
              </use>
            </svg>

            <span [class]="cx('label')" aria-hidden="true">{{andUpLabel}}</span>
            <span [class]="cx('count')">{{item.count}}</span>
          </a>
        </li>
      </ul>
    </div>
  `
            },] }
];
NgAisRatingMenu.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisRatingMenu.propDecorators = {
    andUpLabel: [{ type: Input }],
    attribute: [{ type: Input }],
    max: [{ type: Input }]
};

class NgAisRatingMenuModule {
}
NgAisRatingMenuModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisRatingMenu],
                entryComponents: [NgAisRatingMenu],
                exports: [NgAisRatingMenu],
                imports: [CommonModule],
            },] }
];

class NgAisStats extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('Stats');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            nbHits: 0,
            nbPages: 0,
            page: 0,
            processingTimeMS: 0,
            query: '',
            areHitsSorted: false,
        };
        this.createWidget(connectStats, {}, {
            $$widgetType: 'ais.stats',
        });
    }
    get templateContext() {
        return { state: this.state };
    }
}
NgAisStats.decorators = [
    { type: Component, args: [{
                selector: 'ais-stats',
                template: `
    <div [class]="cx()">
      <ng-container *ngTemplateOutlet="template; context: templateContext">
      </ng-container>

      <span *ngIf="!template" [class]="cx('text')">
        {{state.nbHits}} results found in {{state.processingTimeMS}}ms.
      </span>
    </div>
  `
            },] }
];
NgAisStats.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisStats.propDecorators = {
    template: [{ type: ContentChild, args: [TemplateRef, { static: false },] }]
};

class NgAisStatsModule {
}
NgAisStatsModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisStats],
                entryComponents: [NgAisStats],
                exports: [NgAisStats],
                imports: [CommonModule],
            },] }
];

class NgAisToggle extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('ToggleRefinement');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            canRefine: false,
            sendEvent: undefined,
            value: {
                count: undefined,
                isRefined: false,
                name: '',
                offFacetValue: undefined,
                onFacetValue: undefined,
            },
            createURL: () => '#',
            refine: noop,
        };
    }
    ngOnInit() {
        this.createWidget(connectToggleRefinement, {
            attribute: this.attribute,
            on: this.on,
            off: this.off,
        }, {
            $$widgetType: 'ais.toggleRefinement',
        });
        super.ngOnInit();
    }
    handleChange(event) {
        event.preventDefault();
        event.stopPropagation();
        this.state.refine(this.state.value);
    }
}
NgAisToggle.decorators = [
    { type: Component, args: [{
                selector: 'ais-toggle',
                template: `
    <div [class]='cx()'>
      <label [class]="cx('label')">
        <input
          [class]="cx('checkbox')"
          type='checkbox'
          value='{{state.value.name}}'
          [checked]='state.value.isRefined'
          (change)='handleChange($event)'
        />

        <span [class]="cx('labelText')">
          {{label || state.value.name}}
        </span>

        <span [class]="cx('count')">{{state.value.count}}</span>
      </label>
    </div>
  `
            },] }
];
NgAisToggle.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisToggle.propDecorators = {
    label: [{ type: Input }],
    attribute: [{ type: Input }],
    on: [{ type: Input }],
    off: [{ type: Input }]
};

class NgAisToggleModule {
}
NgAisToggleModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisToggle],
                entryComponents: [NgAisToggle],
                exports: [NgAisToggle],
                imports: [CommonModule],
            },] }
];

class NgAisReverseHighlight {
    constructor() {
        this.highlightedTagName = 'mark';
    }
    get content() {
        return reverseHighlight({
            attribute: this.attribute,
            hit: this.hit,
            highlightedTagName: this.highlightedTagName,
        });
    }
}
NgAisReverseHighlight.decorators = [
    { type: Component, args: [{
                selector: 'ais-reverse-highlight',
                changeDetection: ChangeDetectionStrategy.OnPush,
                template: `<span class="ais-ReverseHighlight" [innerHtml]="content"></span>`
            },] }
];
NgAisReverseHighlight.propDecorators = {
    attribute: [{ type: Input }],
    hit: [{ type: Input }],
    highlightedTagName: [{ type: Input }]
};

class NgAisReverseHighlightModule {
}
NgAisReverseHighlightModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisReverseHighlight],
                exports: [NgAisReverseHighlight],
            },] }
];

class NgAisSnippet {
    constructor() {
        this.highlightedTagName = 'mark';
    }
    get content() {
        return snippet({
            attribute: this.attribute,
            hit: this.hit,
            highlightedTagName: this.highlightedTagName,
        });
    }
}
NgAisSnippet.decorators = [
    { type: Component, args: [{
                selector: 'ais-snippet',
                changeDetection: ChangeDetectionStrategy.OnPush,
                template: `<span class="ais-Snippet" [innerHtml]="content"></span>`
            },] }
];
NgAisSnippet.propDecorators = {
    attribute: [{ type: Input }],
    hit: [{ type: Input }],
    highlightedTagName: [{ type: Input }]
};

class NgAisSnippetModule {
}
NgAisSnippetModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisSnippet],
                exports: [NgAisSnippet],
            },] }
];

class NgAisReverseSnippet {
    constructor() {
        this.highlightedTagName = 'mark';
    }
    get content() {
        return reverseSnippet({
            attribute: this.attribute,
            hit: this.hit,
            highlightedTagName: this.highlightedTagName,
        });
    }
}
NgAisReverseSnippet.decorators = [
    { type: Component, args: [{
                selector: 'ais-reverse-snippet',
                changeDetection: ChangeDetectionStrategy.OnPush,
                template: `<span class="ais-ReverseSnippet" [innerHtml]="content"></span>`
            },] }
];
NgAisReverseSnippet.propDecorators = {
    attribute: [{ type: Input }],
    hit: [{ type: Input }],
    highlightedTagName: [{ type: Input }]
};

class NgAisReverseSnippetModule {
}
NgAisReverseSnippetModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisReverseSnippet],
                exports: [NgAisReverseSnippet],
            },] }
];

class NgAisRangeInput extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('RangeInput');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        // rendering options
        this.currency = '$';
        this.separator = 'to';
        this.submitLabel = 'Go';
        this.precision = 0;
        this.state = {
            range: { min: undefined, max: undefined },
            refine: noop,
            start: [0, 0],
            // TODO: use canRefine & format
            canRefine: false,
            format: {
                from: () => '',
                to: () => '',
            },
            sendEvent: undefined,
        };
    }
    get step() {
        const precision = parseNumberInput(this.precision);
        return 1 / Math.pow(10, precision);
    }
    get canRefine() {
        return this.state.range.min !== this.state.range.max;
    }
    ngOnInit() {
        this.createWidget(connectRange, {
            attribute: this.attribute,
            max: parseNumberInput(this.max),
            min: parseNumberInput(this.min),
            precision: parseNumberInput(this.precision),
        }, {
            $$widgetType: 'ais.rangeInput',
        });
        super.ngOnInit();
    }
    handleChange(event, type) {
        const value = parseNumberInput(event.target.value);
        if (type === 'min') {
            this.minInputValue = value;
        }
        else {
            this.maxInputValue = value;
        }
    }
    handleSubmit(event) {
        event.preventDefault();
        this.state.refine([this.minInputValue, this.maxInputValue]);
    }
}
NgAisRangeInput.decorators = [
    { type: Component, args: [{
                selector: 'ais-range-input',
                template: `
    <div [ngClass]="[
        cx(),
        !canRefine ? cx('', 'noRefinement') : ''
      ]">
      <form
        [class]="cx('form')"
        (submit)="handleSubmit($event)"
        novalidate
      >
        <label [class]="cx('label')">
          <span [class]="cx('currency')">{{currency}}</span>
          <input
            [ngClass]="[
              cx('input'),
              cx('input', 'min')
            ]"
            type="number"
            [min]="state.range.min"
            [max]="state.range.max"
            [placeholder]="state.range.min"
            [value]="minInputValue"
            [step]="step"
            (change)="handleChange($event, 'min')"
          />
        </label>

        <span [class]="cx('separator')">{{separator}}</span>

        <label [class]="cx('label')">
          <span [class]="cx('currency')">{{currency}}</span>
          <input
            [ngClass]="[
              cx('input'),
              cx('input', 'max')
            ]"
            type="number"
            [min]="state.range.min"
            [max]="state.range.max"
            [placeholder]="state.range.max"
            [value]="maxInputValue"
            [step]="step"
            (change)="handleChange($event, 'max')"
          />
        </label>

        <button
          [class]="cx('submit')"
          (click)="handleSubmit($event)"
        >
          {{submitLabel}}
        </button>
      </form>
    </div>
  `
            },] }
];
NgAisRangeInput.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisRangeInput.propDecorators = {
    currency: [{ type: Input }],
    separator: [{ type: Input }],
    submitLabel: [{ type: Input }],
    attribute: [{ type: Input }],
    min: [{ type: Input }],
    max: [{ type: Input }],
    precision: [{ type: Input }]
};

class NgAisRangeInputModule {
}
NgAisRangeInputModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisRangeInput],
                entryComponents: [NgAisRangeInput],
                exports: [NgAisRangeInput],
                imports: [CommonModule],
            },] }
];

class NgAisPanel {
}
NgAisPanel.decorators = [
    { type: Component, args: [{
                selector: 'ais-panel',
                template: `
    <div class="ais-Panel">
      <div *ngIf="header" class="ais-Panel-header">
        {{header}}
      </div>

      <div class="ais-Panel-body">
        <ng-content></ng-content>
      </div>

      <div *ngIf="footer" class="ais-Panel-footer">
        {{footer}}
      </div>
    </div>
  `
            },] }
];
NgAisPanel.propDecorators = {
    header: [{ type: Input }],
    footer: [{ type: Input }]
};

class NgAisPanelModule {
}
NgAisPanelModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisPanel],
                entryComponents: [NgAisPanel],
                exports: [NgAisPanel],
                imports: [CommonModule],
            },] }
];

class NgAisConfigure extends TypedBaseWidget {
    constructor(differs, parentIndex, instantSearchInstance) {
        super('Configure');
        this.differs = differs;
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            refine: noop,
        };
    }
    set searchParameters(values) {
        this.internalSearchParameters = values;
        if (!this.differ && values) {
            this.differ = this.differs.find(values).create();
        }
    }
    ngOnInit() {
        this.createWidget(connectConfigure, {
            searchParameters: this.internalSearchParameters,
        }, {
            $$widgetType: 'ais.configure',
        });
        super.ngOnInit();
    }
    ngDoCheck() {
        if (this.differ) {
            const changes = this.differ.diff(this.internalSearchParameters);
            if (changes) {
                this.state.refine(this.internalSearchParameters);
            }
        }
    }
}
NgAisConfigure.decorators = [
    { type: Component, args: [{
                selector: 'ais-configure',
                template: ''
            },] }
];
NgAisConfigure.ctorParameters = () => [
    { type: KeyValueDiffers },
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisConfigure.propDecorators = {
    searchParameters: [{ type: Input }]
};

class NgAisConfigureModule {
}
NgAisConfigureModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisConfigure],
                entryComponents: [NgAisConfigure],
                exports: [NgAisConfigure],
                imports: [CommonModule],
            },] }
];

class NgAisConfigureRelatedItems extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('ExperimentalConfigureRelatedItems');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
    }
    ngOnInit() {
        this.createWidget(EXPERIMENTAL_connectConfigureRelatedItems, {
            hit: this.hit,
            matchingPatterns: this.matchingPatterns,
            transformSearchParameters: this.transformSearchParameters,
        }, {
            $$widgetType: 'ais.configureRelatedItems',
        });
        super.ngOnInit();
    }
}
NgAisConfigureRelatedItems.decorators = [
    { type: Component, args: [{
                selector: 'ais-experimental-configure-related-items',
                template: ''
            },] }
];
NgAisConfigureRelatedItems.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisConfigureRelatedItems.propDecorators = {
    hit: [{ type: Input }],
    matchingPatterns: [{ type: Input }],
    transformSearchParameters: [{ type: Input }]
};

class NgAisConfigureRelatedItemsModule {
}
NgAisConfigureRelatedItemsModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisConfigureRelatedItems],
                entryComponents: [NgAisConfigureRelatedItems],
                exports: [NgAisConfigureRelatedItems],
                imports: [CommonModule],
            },] }
];

class NgAisQueryRuleCustomData extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('QueryRuleCustomData');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.state = {
            items: [],
        };
    }
    get templateContext() {
        return {
            items: this.state.items,
        };
    }
    ngOnInit() {
        this.createWidget(connectQueryRules, {
            transformItems: this.transformItems,
        }, {
            $$widgetType: 'ais.queryRuleCustomData',
        });
        super.ngOnInit();
    }
}
NgAisQueryRuleCustomData.decorators = [
    { type: Component, args: [{
                selector: 'ais-query-rule-custom-data',
                template: `
    <div [class]='cx()'>
      <ng-container *ngTemplateOutlet='template; context: templateContext'>
      </ng-container>

      <div *ngIf='!template'>
        <div *ngFor='let item of state.items'>
          <pre>{{ item | json }}</pre>
        </div>
      </div>
    </div>
  `
            },] }
];
NgAisQueryRuleCustomData.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisQueryRuleCustomData.propDecorators = {
    template: [{ type: ContentChild, args: [TemplateRef, { static: false },] }],
    transformItems: [{ type: Input }]
};

class NgAisQueryRuleCustomDataModule {
}
NgAisQueryRuleCustomDataModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisQueryRuleCustomData],
                entryComponents: [NgAisQueryRuleCustomData],
                exports: [NgAisQueryRuleCustomData],
                imports: [CommonModule],
            },] }
];

class NgAisQueryRuleContext extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance) {
        super('QueryRuleContext');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
    }
    ngOnInit() {
        this.createWidget(connectQueryRules, {
            trackedFilters: this.trackedFilters,
            transformRuleContexts: this.transformRuleContexts,
        }, {
            $$widgetType: 'ais.queryRuleContext',
        });
        super.ngOnInit();
    }
}
NgAisQueryRuleContext.decorators = [
    { type: Component, args: [{
                selector: 'ais-query-rule-context',
                template: ''
            },] }
];
NgAisQueryRuleContext.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] }
];
NgAisQueryRuleContext.propDecorators = {
    trackedFilters: [{ type: Input }],
    transformRuleContexts: [{ type: Input }]
};

class NgAisQueryRuleContextModule {
}
NgAisQueryRuleContextModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisQueryRuleContext],
                entryComponents: [NgAisQueryRuleContext],
                exports: [NgAisQueryRuleContext],
                imports: [CommonModule],
            },] }
];

class NgAisVoiceSearch extends TypedBaseWidget {
    constructor(parentIndex, instantSearchInstance, zone) {
        super('VoiceSearch');
        this.parentIndex = parentIndex;
        this.instantSearchInstance = instantSearchInstance;
        this.zone = zone;
        // rendering options
        this.buttonTitle = 'Search by voice';
        this.disabledButtonTitle = 'Search by voice (not supported on this browser)';
        this.state = {
            isBrowserSupported: undefined,
            isListening: undefined,
            toggleListening: noop,
            voiceListeningState: {
                status: 'initial',
                transcript: '',
                isSpeechFinal: false,
                errorCode: undefined,
            },
        };
        this.templateContext = {
            status: 'initial',
            errorCode: undefined,
            transcript: '',
            isSpeechFinal: false,
            isListening: false,
            isBrowserSupported: false,
        };
        this.handleClick = (event) => {
            event.currentTarget.blur();
            this.state.toggleListening();
        };
        this.isNotAllowedError = () => this.state.voiceListeningState.status === 'error' &&
            this.state.voiceListeningState.errorCode === 'not-allowed';
        this.updateState = (state) => {
            this.zone.run(() => {
                this.templateContext = {
                    status: state.voiceListeningState.status,
                    errorCode: state.voiceListeningState.errorCode,
                    transcript: state.voiceListeningState.transcript,
                    isSpeechFinal: state.voiceListeningState.isSpeechFinal,
                    isListening: state.isListening,
                    isBrowserSupported: state.isBrowserSupported,
                };
                this.state = state;
            });
        };
    }
    ngOnInit() {
        this.createWidget(connectVoiceSearch, {
            searchAsYouSpeak: this.searchAsYouSpeak,
        }, {
            $$widgetType: 'ais.voiceSearch',
        });
        super.ngOnInit();
    }
}
NgAisVoiceSearch.decorators = [
    { type: Component, args: [{
                selector: 'ais-voice-search',
                template: `
    <div [class]="cx()">
      <button
        type="button"
        [class]="cx('button')"
        [title]="state.isBrowserSupported ? buttonTitle : disabledButtonTitle"
        [disabled]="!state.isBrowserSupported"
        (click)="handleClick($event)"
      >
        <ng-container *ngTemplateOutlet="button ? button : defaultButton; context: templateContext"></ng-container>
      </button>
      <div [class]="cx('status')">
        <ng-container *ngTemplateOutlet="status ? status : defaultStatus; context: templateContext"></ng-container>
      </div>
    </div>

    <ng-template #defaultButton let-status="status" let-errorCode="errorCode" let-isListening="isListening">
      <svg
        xmlns='http://www.w3.org/2000/svg'
        width='16'
        height='16'
        viewBox='0 0 24 24'
        fill='none'
        stroke='currentColor'
        strokeWidth='2'
        strokeLinecap='round'
        strokeLinejoin='round'
      >
        <ng-container *ngIf="isNotAllowedError(); then errorSvgContent else normalSvgContent">
        </ng-container>
        <ng-template #errorSvgContent>
          <line x1="1" y1="1" x2="23" y2="23"></line>
          <path d="M9 9v3a3 3 0 0 0 5.12 2.12M15 9.34V4a3 3 0 0 0-5.94-.6"></path>
          <path d="M17 16.95A7 7 0 0 1 5 12v-2m14 0v2a7 7 0 0 1-.11 1.23"></path>
          <line x1="12" y1="19" x2="12" y2="23"></line>
          <line x1="8" y1="23" x2="16" y2="23"></line>
        </ng-template>
        <ng-template #normalSvgContent>
          <path
            d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"
            [attr.fill]="isListening ? 'currentColor' : 'none'"
          ></path>
          <path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
          <line x1="12" y1="19" x2="12" y2="23"></line>
          <line x1="8" y1="23" x2="16" y2="23"></line>
        </ng-template>
      </svg>
    </ng-template>
    <ng-template #defaultStatus let-transcript="transcript">
      <p>{{transcript}}</p>
    </ng-template>
  `
            },] }
];
NgAisVoiceSearch.ctorParameters = () => [
    { type: NgAisIndex, decorators: [{ type: Inject, args: [forwardRef(() => NgAisIndex),] }, { type: Optional }] },
    { type: NgAisInstantSearch, decorators: [{ type: Inject, args: [forwardRef(() => NgAisInstantSearch),] }] },
    { type: NgZone }
];
NgAisVoiceSearch.propDecorators = {
    button: [{ type: ContentChild, args: ['button', { static: false },] }],
    status: [{ type: ContentChild, args: ['status', { static: false },] }],
    buttonTitle: [{ type: Input }],
    disabledButtonTitle: [{ type: Input }],
    searchAsYouSpeak: [{ type: Input }]
};

class NgAisVoiceSearchModule {
}
NgAisVoiceSearchModule.decorators = [
    { type: NgModule, args: [{
                declarations: [NgAisVoiceSearch],
                entryComponents: [NgAisVoiceSearch],
                exports: [NgAisVoiceSearch],
                imports: [CommonModule],
            },] }
];

// compatibility with different typescript settings:
// - esModuleInterop
// - allowSyntheticDefaultImports
const algoliasearch = (typeof algoliasearchProxy.default === 'function'
    ? algoliasearchProxy.default
    : algoliasearchProxy);
const encode = encodeProxy.default || encodeProxy;
function createSSRSearchClient({ appId, apiKey, httpClient, HttpHeaders, transferState, makeStateKey, options = {}, }) {
    // A custom network request needs to be done, using TransferState of Angular.
    // This is done to make sure the request done backend for SSR doesn't get
    // made again frontend during hydration.
    // For compatibility with both v3 and v4 of algoliasearch, we are overriding the
    // network request function in two places:
    // v4: custom "requester"
    // v3: override "_request" on the prototype
    // since neither v3 uses the requester argument, and v4 use the _request, we
    // can safely do this without checking the version
    const searchClient = algoliasearch(appId, apiKey, Object.assign(Object.assign({}, options), { requester: {
            send({ headers, method, url, data }) {
                const transferStateKey = makeStateKey(`ngais(${data})`);
                if (transferState.hasKey(transferStateKey)) {
                    const response = JSON.parse(transferState.get(transferStateKey, JSON.stringify({})));
                    return Promise.resolve({
                        status: response.status,
                        content: JSON.stringify(response.body),
                        isTimedOut: false,
                    });
                }
                return new Promise((resolve, reject) => {
                    httpClient
                        .request(method, url, {
                        headers,
                        body: data,
                        observe: 'response',
                    })
                        .subscribe(response => {
                        transferState.set(transferStateKey, JSON.stringify(response));
                        resolve({
                            status: response.status,
                            content: JSON.stringify(response.body),
                            isTimedOut: false,
                        });
                    }, response => reject({
                        status: response.status,
                        body: response.body,
                    }));
                });
            },
        } }));
    searchClient.addAlgoliaAgent(`angular (${VERSION$1.full})`);
    searchClient.addAlgoliaAgent(`angular-instantsearch (${VERSION})`);
    searchClient.addAlgoliaAgent(`angular-instantsearch-server (${VERSION})`);
    searchClient._request = (rawUrl, options) => {
        let headers = new HttpHeaders();
        headers = headers.set('content-type', options.method === 'POST'
            ? 'application/x-www-form-urlencoded'
            : 'application/json');
        headers = headers.set('accept', 'application/json');
        const url = rawUrl + (rawUrl.includes('?') ? '&' : '?') + encode(options.headers);
        const transferStateKey = makeStateKey(`ngais(${options.body})`);
        if (transferState.hasKey(transferStateKey)) {
            const response = JSON.parse(transferState.get(transferStateKey, JSON.stringify({})));
            return Promise.resolve({
                statusCode: response.status,
                body: response.body,
                headers: response.headers,
            });
        }
        return new Promise((resolve, reject) => {
            httpClient
                .request(options.method, url, {
                headers,
                body: options.body,
                observe: 'response',
            })
                .subscribe(response => {
                transferState.set(transferStateKey, JSON.stringify(response));
                resolve({
                    statusCode: response.status,
                    body: response.body,
                    headers: response.headers,
                });
            }, response => reject({
                statusCode: response.status,
                body: response.body,
                headers: response.headers,
            }));
        });
    };
    return searchClient;
}

class BaseWidget {
    constructor(widgetName) {
        this.state = {};
        this.updateState = (state, isFirstRendering) => {
            if (isFirstRendering) {
                return Promise.resolve().then(() => {
                    this.state = state;
                });
            }
            this.state = state;
        };
        this.cx = bem(widgetName);
    }
    get parent() {
        if (this.parentIndex) {
            return this.parentIndex;
        }
        return this.instantSearchInstance;
    }
    createWidget(connector, options = {}, additionalWidgetProperties = {}) {
        this.widget = Object.assign(Object.assign({}, connector(this.updateState, noop)(options)), additionalWidgetProperties);
    }
    ngOnInit() {
        this.parent.addWidgets([this.widget]);
    }
    ngOnDestroy() {
        if (isPlatformBrowser(this.instantSearchInstance.platformId)) {
            this.parent.removeWidgets([this.widget]);
        }
    }
    /**
     * Helper to generate class names for an item
     * @param item element to generate a class name for
     */
    getItemClass(item) {
        const className = this.cx('item');
        if (item.isRefined) {
            return `${className} ${this.cx('item', 'selected')}`;
        }
        return className;
    }
}
BaseWidget.propDecorators = {
    autoHideContainer: [{ type: Input }]
};

const NGIS_MODULES = [
    NgAisInstantSearchModule,
    NgAisIndexModule,
    NgAisHitsModule,
    NgAisSearchBoxModule,
    NgAisClearRefinementsModule,
    NgAisMenuModule,
    NgAisPaginationModule,
    NgAisRefinementListModule,
    NgAisHitsPerPageModule,
    NgAisSortByModule,
    NgAisNumericMenuModule,
    NgAisStatsModule,
    NgAisToggleModule,
    NgAisInfiniteHitsModule,
    NgAisCurrentRefinementsModule,
    NgAisHierarchicalMenuModule,
    NgAisRatingMenuModule,
    NgAisRangeSliderModule,
    NgAisBreadcrumbModule,
    NgAisHighlightModule,
    NgAisReverseHighlightModule,
    NgAisSnippetModule,
    NgAisReverseSnippetModule,
    NgAisRangeInputModule,
    NgAisPanelModule,
    NgAisConfigureModule,
    NgAisConfigureRelatedItemsModule,
    NgAisQueryRuleCustomDataModule,
    NgAisQueryRuleContextModule,
    NgAisVoiceSearchModule,
];
class NgAisRootModule {
}
NgAisRootModule.decorators = [
    { type: NgModule, args: [{
                exports: NGIS_MODULES,
                imports: [NgAisInstantSearchModule.forRoot()],
            },] }
];
class NgAisModule {
    static forRoot() {
        return { ngModule: NgAisRootModule };
    }
}
NgAisModule.decorators = [
    { type: NgModule, args: [{ imports: NGIS_MODULES, exports: NGIS_MODULES },] }
];

/**
 * Generated bundle index. Do not edit.
 */

export { BaseWidget, NgAisBreadcrumbModule, NgAisClearRefinementsModule, NgAisConfigureModule, NgAisConfigureRelatedItemsModule, NgAisCurrentRefinementsModule, NgAisHierarchicalMenuModule, NgAisHighlightModule, NgAisHitsModule, NgAisHitsPerPageModule, NgAisIndex, NgAisIndexModule, NgAisInfiniteHitsModule, NgAisInstantSearch, NgAisInstantSearchModule, NgAisMenuModule, NgAisModule, NgAisNumericMenuModule, NgAisPaginationModule, NgAisPanelModule, NgAisQueryRuleContextModule, NgAisQueryRuleCustomDataModule, NgAisRangeInputModule, NgAisRangeSliderModule, NgAisRatingMenuModule, NgAisRefinementListModule, NgAisReverseHighlightModule, NgAisReverseSnippetModule, NgAisRootModule, NgAisSearchBoxModule, NgAisSnippetModule, NgAisSortByModule, NgAisStatsModule, NgAisToggleModule, NgAisVoiceSearchModule, TypedBaseWidget, createSSRSearchClient, NgAisPanel as ɵa, NgAisBreadcrumb as ɵb, NgAisConfigureRelatedItems as ɵba, NgAisQueryRuleCustomData as ɵbb, NgAisQueryRuleContext as ɵbc, NgAisVoiceSearch as ɵbd, NgAisClearRefinements as ɵc, NgAisCurrentRefinements as ɵd, NgAisHierarchicalMenu as ɵe, NgAisHierarchicalMenuItem as ɵf, NgAisHitsPerPage as ɵg, NgAisHits as ɵh, NgAisHighlight as ɵi, NgAisInfiniteHits as ɵj, NgAisMenu as ɵk, NgAisNumericMenu as ɵl, NgAisPagination as ɵm, NgAisRangeSlider as ɵn, NgAisRefinementList as ɵo, NgAisFacetsSearch as ɵp, NgAisSearchBox as ɵq, NgAisSortBy as ɵr, NgAisRatingMenu as ɵs, NgAisStats as ɵt, NgAisToggle as ɵu, NgAisReverseHighlight as ɵv, NgAisSnippet as ɵw, NgAisReverseSnippet as ɵx, NgAisRangeInput as ɵy, NgAisConfigure as ɵz };
//# sourceMappingURL=angular-instantsearch.js.map