import { Directive, ElementRef, Input, Renderer2, AfterViewInit, OnDestroy, } from '@angular/core'; // interfaces import { IRangeSliderConfig } from '../interfaces'; @Directive({ selector: '[appRangeSlider]', }) export class RangeSliderDirective implements AfterViewInit, OnDestroy { @Input() set rangeSliderConfig(config: IRangeSliderConfig) { this._rangeSliderConfig = config; this.updateRangeSlider(); } @Input() value!: number; private _rangeSliderConfig!: IRangeSliderConfig; // unlisten input private unlistenInput!: () => void; constructor( private elementRef: ElementRef, private renderer: Renderer2 ) {} ngAfterViewInit() { this.updateRangeSlider(); } private updateRangeSlider() { const input: HTMLInputElement = this.elementRef .nativeElement as HTMLInputElement; const thumbSelector = '.range-slider-thumb'; const thumb = input.parentElement?.querySelector( thumbSelector ) as HTMLElement; if (!input || !thumb) return; // initial update this.updateThumb(input, thumb); // update on input events this.unlistenInput = this.renderer.listen(input, 'input', () => this.updateThumb(input, thumb) ); } private updateThumb(input: HTMLInputElement, thumb: HTMLElement) { const { min, max } = this._rangeSliderConfig; // clamp value between min/max so percent is always 0–100 const safeValue = Math.min(Math.max(this.value, min), max); const percent = ((safeValue - min) / (max - min)) * 100; const thumbWidth = thumb.offsetWidth; const trackWidth = input.offsetWidth; // usable width so thumb edges align exactly with track edges const usableWidth = trackWidth - thumbWidth; const leftPx = (percent / 100) * usableWidth; this.renderer.setStyle(thumb, 'left', `${leftPx}px`); this.renderer.setStyle( input, 'background', `linear-gradient(to right, #3B73ED33 0%, #3B73ED33 ${percent}%, #424242 ${percent}%, #424242 100%)` ); } ngOnDestroy() { if (this.unlistenInput) this.unlistenInput(); } }