UNPKG

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

Version:

Fluid Design System Angular

198 lines (172 loc) 4.01 kB
import { CommonModule } from '@angular/common'; import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, forwardRef, inject, Input, OnDestroy, ViewChild } from '@angular/core'; import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import { BehaviorSubject, Subject, takeUntil } from 'rxjs'; import { Utils } from '../../utils/utils.util'; @Component({ selector: 'nj-slider', templateUrl: './slider.component.html', providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SliderComponent), multi: true } ], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule] }) export class SliderComponent implements AfterViewInit, OnDestroy, ControlValueAccessor { private _initialValue: number; private _currentValue: number; private _max = 100; private _min = 0; private inputValue$ = new BehaviorSubject<number>(this._min); private unsubscribe = new Subject<void>(); private cdr = inject(ChangeDetectorRef); /** * @ignore */ private _onChange = (_: any): void => {}; /** * @ignore */ protected _onTouched = (): void => {}; /** * Slider Id, required if label is set */ @Input() sliderId?: string; /** * Input name */ @Input() name?: string; /** * Slider label */ @Input() label?: string; /** * Minimum value */ @Input() set min(min: number) { if (!Utils.isUndefinedOrNull(min)) { this._min = min; this.updateInputCssPropWithValue(this._currentValue); } } get min(): number { return this._min; } /** * Maximum value */ @Input() set max(max: number) { if (!Utils.isUndefinedOrNull(max)) { this._max = max; this.updateInputCssPropWithValue(this._currentValue); } } get max(): number { return this._max; } /** * Input value */ @Input() set value(val: number) { if (!Utils.isUndefinedOrNull(val)) { this._initialValue = val; } else { this._initialValue = this._min; } this._currentValue = this._initialValue; this.inputValue$.next(this._currentValue); this.cdr.markForCheck(); } get value(): number { return this._initialValue; } /** * Slider input step */ @Input() step: number = 0.1; /** * Whether input is disabled or not */ @Input() isDisabled = false; @ViewChild('input') input: ElementRef; ngAfterViewInit() { this.inputValue$.pipe(takeUntil(this.unsubscribe)).subscribe((val) => { this.updateInputCssPropWithValue(val); }); } ngOnDestroy() { this.unsubscribe.next(); this.unsubscribe.complete(); } /** * Implemented as part of ControlValueAccessor. * @ignore */ writeValue(value: number): void { this.value = value; } /** * Implemented as part of ControlValueAccessor. * @ignore */ registerOnChange(fn: any): void { this._onChange = fn; } /** * Implemented as part of ControlValueAccessor. * @ignore */ registerOnTouched(fn: any): void { this._onTouched = fn; } /** * Implemented as part of ControlValueAccessor. * @ignore */ setDisabledState(isDisabled: boolean): void { this.isDisabled = isDisabled; this.cdr.markForCheck(); } /** * @ignore */ updateValue(event: Event) { // @ts-ignore const newVal = event?.target?.value; if (newVal !== this._currentValue) { this._currentValue = newVal; this.writeValue(newVal); this._onChange(newVal); } } /** * @ignore */ updateInputCssPropWithValue(value: number) { if (!this.input?.nativeElement || Utils.isUndefinedOrNull(value)) { return; } let percentage = (100 * (value - this.min)) / (this.max - this.min); percentage = isNaN(percentage) ? 0 : percentage; this.input.nativeElement.style.setProperty('--nj-slider-track-position', `${percentage}% 100%`); } }