All files / accordion si-accordion.component.ts

86.36% Statements 19/22
33.33% Branches 3/9
100% Functions 5/5
86.36% Lines 19/22

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                                                1x                         1x   9x   9x   9x         9x 6x     9x 9x 9x 9x 9x 9x 9x     6x       6x     1x   6x       1x              
/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
import {
  AfterContentInit,
  booleanAttribute,
  ChangeDetectionStrategy,
  Component,
  computed,
  contentChildren,
  DestroyRef,
  ElementRef,
  inject,
  input,
  OnChanges
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { ResizeObserverService } from '@siemens/element-ng/resize-observer';
 
import { SiAccordionHCollapseService } from './si-accordion-hcollapse.service';
import { SiAccordionService } from './si-accordion.service';
import { SiCollapsiblePanelComponent } from './si-collapsible-panel.component';
 
const PANEL_MIN_HEIGHT = 100;
 
@Component({
  selector: 'si-accordion',
  template: '<div><ng-content /></div>',
  styleUrl: './si-accordion.component.scss',
  providers: [SiAccordionService],
  changeDetection: ChangeDetectionStrategy.OnPush,
  host: {
    '[class.full-height]': 'fullHeight()',
    '[class.hcollapsed]': 'collapsed()'
  }
})
export class SiAccordionComponent implements AfterContentInit, OnChanges {
  /** @defaultValue true */
  readonly expandFirstPanel = input(true, { transform: booleanAttribute });
  /** @defaultValue false */
  readonly fullHeight = input(false, { transform: booleanAttribute });
  /** @defaultValue false */
  readonly hcollapsed = input(false);
  /**
   * Indicate whether the accordion is collapsed.
   * @internal
   */
  readonly collapsed = computed(
    () => this.accordionHCollapseService?.hcollapsed() ?? this.hcollapsed()
  );
 
  private readonly panels = contentChildren(SiCollapsiblePanelComponent);
  private responsive = false;
  private destroyer = inject(DestroyRef);
  private service = inject(SiAccordionService);
  private resizeObserver = inject(ResizeObserverService);
  private element = inject(ElementRef);
  private accordionHCollapseService = inject(SiAccordionHCollapseService, { optional: true });
 
  ngOnChanges(): void {
    this.service.fullHeight.set(this.fullHeight() && !this.responsive);
  }
 
  ngAfterContentInit(): void {
    this.resizeObserver
      .observe(this.element.nativeElement, 100, true, true)
      .pipe(takeUntilDestroyed(this.destroyer))
      .subscribe(() => this.calcFullHeight());
 
    this.panels().at(0)?.openClose(this.expandFirstPanel(), false);
  }
 
  private calcFullHeight(): void {
    Iif (this.panels?.length) {
      const height = (this.element.nativeElement as HTMLElement).offsetHeight;
      this.responsive = !this.hcollapsed() && height < this.panels.length * PANEL_MIN_HEIGHT;
      this.service.fullHeight.set(this.fullHeight() && !this.responsive);
    }
  }
}