All files / resize-observer si-responsive-container.directive.ts

95.83% Statements 23/24
84.61% Branches 11/13
100% Functions 4/4
95.83% Lines 23/24

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                                    1x                                               1x   62x   62x   62x   62x   62x   62x     62x 62x       62x 62x     62x   6x       62x       5x       5x   5x 5x 5x 5x 5x 5x      
/**
 * Copyright (c) Siemens 2016 - 2025
 * SPDX-License-Identifier: MIT
 */
import { Directive, ElementRef, inject, input, OnDestroy, OnInit, signal } from '@angular/core';
import { Subscription } from 'rxjs';
 
import { ResizeObserverService } from './resize-observer.service';
 
export interface Breakpoints {
  smMinimum: number;
  mdMinimum: number;
  lgMinimum: number;
  xlMinimum: number;
  xxlMinimum: number;
}
 
// keep in sync with the Bootstrap variables
export const BOOTSTRAP_BREAKPOINTS: Breakpoints = {
  smMinimum: 576,
  mdMinimum: 768,
  lgMinimum: 992,
  xlMinimum: 1200,
  xxlMinimum: 1400
};
 
/**
 * Directive to automatically set `si-container-*` classes so Bootstrap column classes work
 * in the context of the container instead of viewport size.
 */
@Directive({
  selector: '[siResponsiveContainer]',
  host: {
    '[class.si-container-xs]': 'xs()',
    '[class.si-container-sm]': 'sm()',
    '[class.si-container-md]': 'md()',
    '[class.si-container-lg]': 'lg()',
    '[class.si-container-xl]': 'xl()',
    '[class.si-container-xxl]': 'xxl()'
  },
  exportAs: 'siResponsiveContainer'
})
export class SiResponsiveContainerDirective implements OnInit, OnDestroy {
  /** @defaultValue false */
  readonly xs = signal(false);
  /** @defaultValue false */
  readonly sm = signal(false);
  /** @defaultValue false */
  readonly md = signal(false);
  /** @defaultValue false */
  readonly lg = signal(false);
  /** @defaultValue false */
  readonly xl = signal(false);
  /** @defaultValue false */
  readonly xxl = signal(false);
 
  /** @defaultValue 100 */
  readonly resizeThrottle = input(100);
  readonly breakpoints = input<Breakpoints>();
 
  private subs?: Subscription;
 
  private element = inject(ElementRef);
  private service = inject(ResizeObserverService);
 
  ngOnInit(): void {
    this.subs = this.service
      .observe(this.element.nativeElement, this.resizeThrottle(), true)
      .subscribe(event => this.setResponsiveSize(event.width, event.height));
  }
 
  ngOnDestroy(): void {
    this.subs?.unsubscribe();
  }
 
  private setResponsiveSize(width: number, height: number): void {
    Iif (!width && !height) {
      // element is not visible, no point in changing anything
      return;
    }
    const breakpoints = this.breakpoints() ?? BOOTSTRAP_BREAKPOINTS;
 
    this.xs.set(width < breakpoints.smMinimum);
    this.sm.set(width >= breakpoints.smMinimum && width < breakpoints.mdMinimum);
    this.md.set(width >= breakpoints.mdMinimum && width < breakpoints.lgMinimum);
    this.lg.set(width >= breakpoints.lgMinimum && width < breakpoints.xlMinimum);
    this.xl.set(width >= breakpoints.xlMinimum && width < breakpoints.xxlMinimum);
    this.xxl.set(width >= breakpoints.xxlMinimum);
  }
}