All files / select/select-input si-select-input.component.ts

100% Statements 20/20
100% Branches 1/1
100% Functions 3/3
100% Lines 19/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105                                                                                                    1x 114x           114x           114x   114x 114x 114x 114x             114x   114x 114x     114x 114x 114x 114x       4x 1x                     40x 40x      
/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
import {
  booleanAttribute,
  ChangeDetectionStrategy,
  Component,
  computed,
  HostListener,
  inject,
  input,
  output,
  TemplateRef
} from '@angular/core';
import { SiAutoCollapsableListModule } from '@siemens/element-ng/auto-collapsable-list';
import { addIcons, elementDown2, SiIconComponent } from '@siemens/element-ng/icon';
import { SiTranslatePipe, TranslatableString } from '@siemens/element-translate-ng/translate';
 
import {
  SI_SELECT_OPTIONS_STRATEGY,
  SiSelectOptionsStrategy
} from '../options/si-select-options-strategy';
import { SiSelectOptionComponent } from '../select-option/si-select-option.component';
import { SiSelectSelectionStrategy } from '../selection/si-select-selection-strategy';
import { SelectOption } from '../si-select.types';
 
@Component({
  selector: 'si-select-input',
  imports: [SiAutoCollapsableListModule, SiIconComponent, SiSelectOptionComponent, SiTranslatePipe],
  templateUrl: './si-select-input.component.html',
  styleUrl: './si-select-input.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    // In readonly mode, the select needs to be announced as a textbox.
    // Otherwise, screen-reader won't announce the readonly state.
    class: 'select focus-none dropdown-toggle d-flex align-items-center ps-4',
    'aria-autocomplete': 'none',
    '[attr.role]': 'readonly() ? "textbox": "combobox"',
    '[attr.aria-haspopup]': 'readonly() ? undefined : "listbox"',
    '[attr.aria-expanded]': 'readonly() ? undefined : open()',
    '[attr.aria-controls]': 'readonly() ? undefined : controls()',
    '[attr.aria-readonly]': 'readonly()',
    '[attr.aria-labelledby]': 'labeledBy()',
    '[attr.aria-disabled]': 'selectionStrategy.disabled()',
    '[attr.tabindex]': 'selectionStrategy.disabled() ? "-1" : "0"',
    '[class.disabled]': 'selectionStrategy.disabled()',
    '[class.active]': 'open()'
  }
})
export class SiSelectInputComponent<T> {
  readonly baseId = input.required<string>();
  /**
   * Aria labelledby of the select.
   *
   * @defaultValue null
   */
  readonly labelledby = input<string | null>(null);
  /**
   * Aria label of the select.
   *
   * @defaultValue null
   */
  readonly ariaLabel = input<string | null>(null);
  /** @defaultValue false */
  readonly open = input(false, { transform: booleanAttribute });
  readonly placeholder = input<TranslatableString>();
  readonly controls = input.required<string>();
  readonly optionTemplate = input<
    TemplateRef<{
      $implicit: SelectOption<T>;
    }>
  >();
 
  /** @defaultValue false */
  readonly readonly = input(false, { transform: booleanAttribute });
 
  readonly openListbox = output<void>();
  protected readonly selectionStrategy = inject<SiSelectSelectionStrategy<T>>(
    SiSelectSelectionStrategy<T>
  );
  private readonly selectOptions = inject<SiSelectOptionsStrategy<T>>(SI_SELECT_OPTIONS_STRATEGY);
  protected readonly selectedRows = this.selectOptions.selectedRows;
  protected readonly labeledBy = computed(() => `${this.baseId()}-aria-label ${this.labelledby()}`);
  protected readonly icons = addIcons({ elementDown2 });
 
  @HostListener('blur')
  protected blur(): void {
    if (!this.open()) {
      this.selectionStrategy.onTouched();
    }
  }
 
  @HostListener('click')
  @HostListener('keydown.arrowDown', ['$event'])
  @HostListener('keydown.alt.arrowDown', ['$event'])
  @HostListener('keydown.arrowUp', ['$event'])
  @HostListener('keydown.enter')
  @HostListener('keydown.space')
  protected click(event?: Event): void {
    event?.preventDefault();
    this.openListbox.emit();
  }
}