{"version":3,"file":"spinque-angular-ui-search-field.mjs","sources":["../../../projects/spinque-angular-ui/search-field/src/search-field.component.ts","../../../projects/spinque-angular-ui/search-field/src/search-field.component.html","../../../projects/spinque-angular-ui/search-field/spinque-angular-ui-search-field.ts"],"sourcesContent":["import {\n  Component,\n  Input,\n  Output,\n  EventEmitter,\n  OnInit,\n  ContentChild,\n  TemplateRef,\n  SimpleChanges,\n  OnChanges,\n  ViewChild,\n  ChangeDetectionStrategy,\n  ElementRef,\n} from '@angular/core';\nimport { Query, ResultItem } from '@spinque/query-api';\nimport { Observable, of } from 'rxjs';\nimport { debounceTime, switchMap, filter, tap } from 'rxjs/operators';\nimport { SpinqueApiService } from '@spinque/angular-ui';\nimport { MatAutocompleteModule, MatAutocompleteTrigger } from '@angular/material/autocomplete';\nimport { MatButtonModule } from '@angular/material/button';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatFormFieldModule } from '@angular/material/form-field';\nimport { CommonModule } from '@angular/common';\nimport { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';\n\n/**\n * A search bar with support for autosuggest, working with SpinqueQuery stacks.\n */\n@Component({\n    selector: 'spinque-search-field',\n    imports: [\n        CommonModule,\n        FormsModule,\n        ReactiveFormsModule,\n        MatFormFieldModule,\n        MatIconModule,\n        MatButtonModule,\n        MatAutocompleteModule\n    ],\n    templateUrl: './search-field.component.html',\n    changeDetection: ChangeDetectionStrategy.OnPush,\n    styles: [\n        `\n      ::placeholder {\n        color: var(--mat-list-list-item-supporting-text-color) !important;\n      }\n      .search-field {\n        box-sizing: border-box;\n        display: flex;\n        flex-direction: row;\n        height: 48px;\n        background-color: var(--mat-form-field-filled-container-color) !important;\n        transition: background-color .15s ease;\n        border: 0 !important;\n        padding-left: 16px;\n        border-radius: 32px;\n        min-width: 250px;\n        align-items: center;\n        cursor: text;\n\n        .input-wrapper {\n          flex: 1 1 auto;\n          margin-left: 16px;\n          input {\n            outline: none;\n            width: 100%;\n            border: none;\n            height: 46px;\n            margin: 0;\n            padding: 0;\n            font-size: 16px;\n            background-color: transparent !important;\n          }\n\n        }\n\n        .clear-button {\n          margin: 4px;\n          min-width: 40px;\n          .mat-mdc-icon-button .mat-mdc-button-persistent-ripple {\n            border-radius: 0 !important;\n          }\n        }\n        .search-button {\n          min-height: 40px;\n          border-top-right-radius: 32px;\n          border-bottom-right-radius: 32px;\n          margin: 4px;\n          min-width: 40px;\n          color: var(--mat-button-filled-label-text-color);\n          background-color: var(--mat-button-filled-container-color);\n          border-radius: 100px;\n\n          .mat-mdc-icon-button .mat-mdc-button-persistent-ripple {\n            border-radius: 0 !important;\n          }\n        }\n\n        &:has(:focus) {\n          background-color: white !important;\n          box-shadow: 0 1px 2px 0 rgba(60,64,67,0.35), 0 1px 4px 1px rgba(60,64,67,0.2);\n          border: 1px solid rgb(232,234,237);\n        }\n      \n      }\n    `,\n    ]\n})\nexport class SpinqueSearchField implements OnInit, OnChanges {\n  /**\n   * Set the value of the input field\n   */\n  @Input() value?: string;\n\n  /**\n   * Assumes that the top endpoint in the query is the endpoint to use for suggest\n   */\n  @Input() query?: Query;\n\n  /**\n   * Name of the parameter in the suggest endpoint to fill with the query when suggesting\n   */\n  @Input() parameterName?: string;\n\n  /**\n   * Placeholder value for the search input\n   */\n  @Input() placeholder = 'Search';\n  @Input() showSearchButton = true;\n  @Input() icon?: string;\n  @Input() ariaLabelClearButton?: string = 'Clear';\n  @Input() ariaLabelSearchButton?: string= 'Search';\n  @Input() ariaLabelSearchFieldInput?: string = 'Main search field'\n\n  /**\n   * Delay between keystrokes for submitting the next queryChange\n   */\n  @Input() debounceTime = 100;\n\n  /**\n   * Outputs the query whenever it changes\n   */\n  @Output() queryChange = new EventEmitter<string>();\n\n  /**\n   * Outputs the query when the uses presses 'enter', the search button or a suggestion\n   */\n  @Output() search = new EventEmitter<string>();\n\n  @ContentChild(TemplateRef) template: TemplateRef<any> | null = null;\n\n  @ViewChild(MatAutocompleteTrigger) autocomplete?: MatAutocompleteTrigger;\n\n  autocompleteControl?: FormControl<string | null>;\n  autocomplete$?: Observable<any>;\n\n  hasAutocompleteResults = false;\n\n  /**\n   * Mapping from SpinqueResultItem to string\n   */\n  @Input() itemToText: (item: ResultItem) => string = (item) =>\n    item ? (item.tuple[0] as string) : '';\n\n  @ViewChild('input', { read: ElementRef }) input!: ElementRef<HTMLElement>;\n\n  constructor(private api: SpinqueApiService) {}\n\n  ngOnInit() {\n    if (this.query && !this.parameterName) {\n      // Pick the first parameter by default\n      this.parameterName = Object.keys(this.query.parameters || [])[0];\n    }\n\n    const parameterValue = this.query && this.query.parameters && this.parameterName\n      ? this.query.parameters[this.parameterName]\n      : '';\n\n    this.autocompleteControl = new FormControl<string | null>(this.value || parameterValue);\n    this.autocompleteControl.valueChanges.pipe(\n      // delay emits\n      debounceTime(this.debounceTime))\n      .subscribe((value) => {\n        this.queryChange.emit(value || '');\n      }\n    );\n\n    this.autocomplete$ = this.autocompleteControl.valueChanges.pipe(\n      filter(\n        () => this.query !== undefined && this.parameterName !== undefined\n      ),\n      // delay emits\n      debounceTime(this.debounceTime),\n      // with switch map we cancel previous subscribed events, before creating new once\n      switchMap((value) => {\n        if (value !== '' && this.query) {\n          if (this.parameterName && this.query) {\n            if (this.query.parameters === undefined) {\n              this.query.parameters = {};\n              this.query.parameters[this.parameterName] = value || '';\n            } else {\n              this.query.parameters[this.parameterName] = value || '';\n            }\n          }\n          return this.api.getResults(this.query).pipe(tap(r => this.hasAutocompleteResults = r.items.length > 0));\n        } else {\n          // if no value is present, return null\n          return of(null);\n        }\n      })\n    );\n  }\n\n  ngOnChanges(changes: SimpleChanges) {\n    // @TBD. because of this any parameter change from outside this component triggers a valueChange, and thus an http request\n    // if (changes.query && changes.query.currentValue && this.autocompleteControl) {\n    //   const value = this.query.endpoints.find(e => e.name === this.endpointName).parameters[this.parameterName];\n    //   this.autocompleteControl.patchValue(value);\n    // }\n    if (changes['query']) {\n      this.ngOnInit();\n    }\n    if (changes['value'] && this.autocompleteControl) {\n      this.autocompleteControl.setValue(changes['value'].currentValue);\n    }\n  }\n\n  submit() {\n    if (!this.autocompleteControl) {\n      return;\n    }\n    this.autocomplete?.closePanel();\n    const q = this.autocompleteControl.value;\n    this.search.emit(q || '');\n  }\n\n  clear() {\n    if (!this.autocompleteControl) {\n      return;\n    }\n    this.autocompleteControl.patchValue('');\n    this.submit();\n  }\n}\n","<form (ngSubmit)=\"submit()\">\n  <div class=\"search-field\" [ngClass]=\"{ 'hasAutocompleteResults': hasAutocompleteResults }\" (click)=\"input.nativeElement.focus()\">\n    @if (icon) {\n      <mat-icon style=\"margin-right: -6px;\">{{ icon || 'search' }}</mat-icon>\n    }\n    <div class=\"input-wrapper\">\n      @if (autocompleteControl) {\n        <input\n          matInput\n          [placeholder]=\"placeholder\"\n          [matAutocomplete]=\"auto\"\n          [formControl]=\"autocompleteControl\"\n          name=\"autocompleteControl\"\n          autocomplete=\"off\"\n          [attr.aria-label]=\"ariaLabelSearchFieldInput\"\n          #input />\n      }\n    </div>\n    @if (autocompleteControl && autocompleteControl.value) {\n      <button\n        type=\"button\"\n        class=\"clear-button\"\n        [attr.aria-label]=\"ariaLabelClearButton\"\n        mat-icon-button\n        role=\"button\"\n        (click)=\"clear()\">\n        <mat-icon>clear</mat-icon>\n      </button>\n    }\n    @if (showSearchButton) {\n      <button\n        type=\"submit\"\n        class=\"search-button primary\"\n        [attr.aria-label]=\"ariaLabelSearchButton\"\n        mat-icon-button\n        role=\"button\">\n        <mat-icon>search</mat-icon>\n      </button>\n    }\n  </div>\n  <mat-autocomplete #auto=\"matAutocomplete\" (optionSelected)=\"submit()\">\n    @if (template && autocomplete$ | async; as autocomplete) {\n      @for (item of autocomplete.items; track item) {\n        <mat-option [value]=\"itemToText(item)\">\n          <ng-container *ngTemplateOutlet=\"template; context: { $implicit: item }\" />\n        </mat-option>\n      }\n    }\n  </mat-autocomplete>\n</form>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}