UNPKG

@engie-group/fluid-design-system-angular

Version:

Fluid Design System Angular

220 lines (192 loc) 5.07 kB
import { CommonModule } from '@angular/common'; import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, ElementRef, EventEmitter, Input, OnDestroy, Output, QueryList, ViewChild } from '@angular/core'; import { ControlValueAccessor } from '@angular/forms'; import { Subject, takeUntil } from 'rxjs'; import { Utils } from '../../utils/utils.util'; import { SegmentedControlButtonComponent } from '../segmented-control-button/segmented-control-button.component'; import { SegmentedControlSize } from './segmented-control.model'; @Component({ selector: 'nj-segmented-control', templateUrl: './segmented-control.component.html', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [SegmentedControlButtonComponent, CommonModule] }) export class SegmentedControlComponent implements ControlValueAccessor, AfterViewInit, OnDestroy { private readonly segmentedControlClass = 'nj-segmented-control'; /** * @ignore */ private unsubscribe: Subject<void> = new Subject<void>(); /** * @ignore */ private _onChange = (_: any): void => {}; /** * @ignore */ private _onTouched = (): void => {}; /** * @ignore */ private _isDisabled: boolean; /** * @ignore */ private _value: string; /** * @ignore */ public segmentedButtons: SegmentedControlButtonComponent[]; /** * Selected value */ @Input() set value(value: string) { this._value = value; this.setActive(value); } get value(): string { return this._value; } /** * Selected aria label */ @Input() ariaLabel: string; /** * Overrides disabled state on all buttons */ @Input() set isDisabled(value: boolean) { this._isDisabled = value; this.setButtonsIsDisabled(); } get isDisabled(): boolean { return this._isDisabled; } /** * Segmented Control size */ @Input() size: SegmentedControlSize = 'md'; /** * @ignore */ @ContentChildren(SegmentedControlButtonComponent) segmentedButtonsList: QueryList<SegmentedControlButtonComponent>; /** * @ignore */ @ViewChild('segmentedControl') segmentedControl: ElementRef<HTMLDivElement>; /** * Output that emits value change */ @Output() valueChange: EventEmitter<string> = new EventEmitter<string>(); constructor(private cdr: ChangeDetectorRef) {} ngAfterViewInit() { // A render is being done after view init so setTimeout allows us to delay any attribute modification // in the call stack, so it can be taken account on next render only setTimeout(() => { this.segmentedButtons = this.segmentedButtonsList?.toArray(); this.setButtonsIsDisabled(); this.initializeClickListener(); if (this.value) { this.setActive(this.value); } }); } private setButtonsIsDisabled() { if (!Utils.isUndefinedOrNull(this.isDisabled) && this.segmentedButtons) { for (const segmentedButton of this.segmentedButtons) { segmentedButton.setIsDisabled(this.isDisabled); } } } ngOnDestroy() { this.unsubscribe.next(); this.unsubscribe.complete(); } /** * @ignore */ private initializeClickListener() { if (Utils.isUndefinedOrNull(this.segmentedButtons)) { return; } this.segmentedButtons.forEach((button, value) => { button.buttonClick.pipe(takeUntil(this.unsubscribe)).subscribe((_) => { button.isSelected = true; this.writeValue(button.value); }); }); } private setActive(buttonValue: string) { if (!this.segmentedButtons) { return; } for (const button of this.segmentedButtons) { if (button?.value === buttonValue) { button.setIsSelected(true); const selectedBoundingRect = button.getClientBoundingRect(); const segmentedControlBoundingRect = this.segmentedControl.nativeElement.getBoundingClientRect(); const segmentedControlStyle = this.segmentedControl?.nativeElement?.style; segmentedControlStyle.setProperty('--nj-sc-btn-selected-width', `${selectedBoundingRect.width}px`); segmentedControlStyle.setProperty( '--nj-sc-btn-selected-right', `${segmentedControlBoundingRect.right - selectedBoundingRect.right}px` ); } else { button.setIsSelected(false); } } } /** * @ignore */ getSizeClass(): string { if (!this.size || this.size === 'md') { return; } return `${this.segmentedControlClass}--${this.size}`; } /** * @ignore */ writeValue(value: any): void { if (value === this.value) { return; } this.setActive(value); this.value = value; } /** * @ignore */ registerOnChange(fn: any): void { this._onChange = fn; } /** * @ignore */ registerOnTouched(fn: any): void { this._onTouched = fn; } /** * @ignore */ setDisabledState?(isDisabled: boolean): void { this.isDisabled = isDisabled; this.cdr.markForCheck(); } }