import * as i0 from '@angular/core';
import { forwardRef, EventEmitter, Component, ChangeDetectionStrategy, ViewChild, Input, Output, NgModule } from '@angular/core';
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
import { fromEvent } from 'rxjs';
import { tap, pluck, map, distinctUntilChanged, takeUntil } from 'rxjs/operators';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i2 from 'ng-devui/popover';
import { PopoverModule } from 'ng-devui/popover';

const SLIDER_CONTROL_VALUE_ACCESSOR = {
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => SliderComponent),
    multi: true
};
class SliderComponent {
    constructor(cdr) {
        this.cdr = cdr;
        this.isDragging = false;
        this.isHovering = false;
        this.showValuePopover = false;
        this.max = 100;
        this.min = 0;
        this.step = 1;
        this.disabled = false;
        this.afterChange = new EventEmitter();
        this.tipsRenderer = (value) => `${value}`;
        this.onTouchedCallback = () => {
        };
        this.onChangeCallback = (v) => {
        };
    }
    ngOnInit() {
        this.checkRangeValues(this.min, this.max);
        this.checkStepValue();
        this.toggleDisabled(this.disabled);
        if (this.value === null) {
            this.setValue(this.ensureValueInRange(null));
        }
    }
    ngOnChanges(changes) {
        if (Object.prototype.hasOwnProperty.call(changes, 'min')
            || Object.prototype.hasOwnProperty.call(changes, 'max')
            || Object.prototype.hasOwnProperty.call(changes, 'step')) {
            this.checkRangeValues(this.min, this.max);
            this.checkStepValue();
        }
    }
    ngAfterViewInit() {
        this.registerMouseEventsListeners();
        this.registerHandleHoverPopoverListener();
        this.toggleDisabled(this.disabled);
    }
    registerOnChange(fn) {
        this.onChangeCallback = fn;
    }
    registerOnTouched(fn) {
        this.onTouchedCallback = fn;
    }
    setDisabledState(isDisabled) {
        this.disabled = isDisabled;
        this.toggleDisabled(isDisabled);
    }
    writeValue(newValue) {
        this.setValue(this.ensureValueInRange(newValue), false);
    }
    checkRangeValues(minValue, maxValue) {
        if (maxValue <= minValue) {
            throw new Error(`max value must be greater than min value`);
        }
    }
    checkStepValue() {
        if (this.step < 0 || !this.step) {
            throw new Error('step value must be greater than 0.');
        }
        else if ((this.max - this.min) % this.step) {
            throw new Error('(max - min) must be divisible by step.');
        }
    }
    ratioToValue(ratio, min, max, step) {
        let value = (max - min) * ratio + min;
        if (step > 0) {
            value = Math.round(value / step) * step;
        }
        return this.clamp(min, value, max);
    }
    convertHandlePositionToRatio(handleX, startX, totalLength) {
        return this.clamp(0, (handleX - startX) / totalLength, 1);
    }
    clamp(min, n, max) {
        return Math.max(min, Math.min(n, max));
    }
    updateStyle(percentage) {
        percentage = Math.min(1, Math.max(0, percentage));
        this.sliderTrack.nativeElement.style.width = `${percentage * 100}%`;
        this.sliderHandle.nativeElement.style.left = `calc(${percentage * 100}% - 7px)`;
    }
    registerMouseEventsListeners() {
        this.dragStartListener = fromEvent(this.slider.nativeElement, 'mousedown').pipe(tap((e) => {
            e.stopPropagation();
            e.preventDefault();
        }), pluck('pageX'), map((position) => this.mousePositionToAdaptiveValue(position)));
        this.dragEndListener = fromEvent(document, 'mouseup');
        this.dragMoveListener = fromEvent(document, 'mousemove').pipe(tap((e) => {
            e.stopPropagation();
            e.preventDefault();
        }), pluck('pageX'), distinctUntilChanged(), map((position) => this.mousePositionToAdaptiveValue(position)), distinctUntilChanged(), takeUntil(this.dragEndListener));
    }
    getSliderPagePosition() {
        const rect = this.slider.nativeElement.getBoundingClientRect();
        const window = this.slider.nativeElement.ownerDocument.defaultView;
        return rect.left + window.pageXOffset;
    }
    getRailLength() {
        return this.sliderRail.nativeElement.clientWidth;
    }
    mousePositionToAdaptiveValue(handleX) {
        const sliderStartX = this.getSliderPagePosition();
        const sliderLength = this.getRailLength();
        const ratio = this.convertHandlePositionToRatio(handleX, sliderStartX, sliderLength);
        const value = this.ratioToValue(ratio, this.min, this.max, this.step);
        return parseFloat(value.toFixed(this.getDecimals(this.step)));
    }
    getDecimals(value) {
        const valueString = value.toString();
        const integerLength = valueString.indexOf('.') + 1;
        return integerLength >= 0 ? valueString.length - integerLength : 0;
    }
    mouseStartMoving(value) {
        this.handleController(true);
        this.setValue(value);
    }
    mouseMoving(value) {
        this.setValue(value);
        this.cdr.markForCheck();
    }
    mouseStopMoving() {
        this.afterChange.emit(this.value);
        this.handleController(false);
        this.onTouchedCallback();
        this.cdr.markForCheck();
    }
    subscribeMouseActions(mouseActions = ['start', 'move', 'end']) {
        if (mouseActions.indexOf('start') !== -1 && this.dragStartListener && !this.dragStartHandler) {
            this.dragStartHandler = this.dragStartListener.subscribe(this.mouseStartMoving.bind(this));
        }
        if (mouseActions.indexOf('move') !== -1 && this.dragMoveListener && !this.dragMoveHandler) {
            this.dragMoveHandler = this.dragMoveListener.subscribe(this.mouseMoving.bind(this));
        }
        if (mouseActions.indexOf('end') !== -1 && this.dragEndListener && !this.dragEndHandler) {
            this.dragEndHandler = this.dragEndListener.subscribe(this.mouseStopMoving.bind(this));
        }
    }
    unsubscribeMouseActions(dragStages = ['start', 'move', 'end']) {
        if (dragStages.indexOf('start') !== -1 && this.dragStartHandler) {
            this.dragStartHandler.unsubscribe();
            this.dragStartHandler = null;
        }
        if (dragStages.indexOf('move') !== -1 && this.dragMoveHandler) {
            this.dragMoveHandler.unsubscribe();
            this.dragMoveHandler = null;
        }
        if (dragStages.indexOf('end') !== -1 && this.dragEndHandler) {
            this.dragEndHandler.unsubscribe();
            this.dragEndHandler = null;
        }
    }
    handleController(movable) {
        if (movable) {
            this.isDragging = true;
            this.showValuePopover = this.showValuePopoverController();
            this.subscribeMouseActions(['move', 'end']);
        }
        else {
            this.isDragging = false;
            this.showValuePopover = this.showValuePopoverController();
            this.unsubscribeMouseActions(['move', 'end']);
        }
    }
    toggleDisabled(disabled) {
        if (disabled) {
            this.unsubscribeMouseActions();
        }
        else {
            this.subscribeMouseActions(['start']);
        }
    }
    setValue(value, triggerOnChanges = true) {
        if (this.value !== value) {
            this.value = value;
            this.updateTrackAndHandle();
        }
        if (triggerOnChanges) {
            this.onChangeCallback(this.value);
        }
    }
    ensureValueInRange(value) {
        let safeValue;
        if (!this.valueMustBeValid(value)) {
            safeValue = this.min;
        }
        else {
            safeValue = this.clamp(this.min, value, this.max);
        }
        return safeValue;
    }
    updateTrackAndHandle() {
        const value = this.value;
        const offset = this.valueToOffset(value);
        this.updateStyle(offset / 100);
        this.cdr.markForCheck();
    }
    valueMustBeValid(value) {
        return !isNaN(typeof value !== 'number' ? parseFloat(value) : value);
    }
    valueToOffset(value) {
        return ((value - this.min) / (this.max - this.min)) * 100;
    }
    registerHandleHoverPopoverListener() {
        const mouseOverListener = fromEvent(this.sliderHandle.nativeElement, 'mouseover');
        const mouseLeaveListener = fromEvent(this.sliderHandle.nativeElement, 'mouseout');
        this.mouseOverHandler = mouseOverListener.subscribe(this.sliderHandlePopoverOnMouseHover.bind(this));
        this.mouseLeaveHandler = mouseLeaveListener.subscribe(this.sliderHandlePopoverOnMouseLeave.bind(this));
    }
    sliderHandlePopoverOnMouseHover() {
        this.isHovering = true;
        this.showValuePopover = this.showValuePopoverController();
        this.cdr.markForCheck();
    }
    sliderHandlePopoverOnMouseLeave() {
        this.isHovering = false;
        this.showValuePopover = this.showValuePopoverController();
        this.cdr.markForCheck();
    }
    unregisterHandleHoverTooltip() {
        this.mouseOverHandler.unsubscribe();
        this.mouseLeaveHandler.unsubscribe();
    }
    showValuePopoverController() {
        return this.isDragging || this.isHovering;
    }
    ngOnDestroy() {
        this.unsubscribeMouseActions();
        this.unregisterHandleHoverTooltip();
    }
}
SliderComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: SliderComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
SliderComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.0", type: SliderComponent, selector: "d-slider", inputs: { max: "max", min: "min", step: "step", disabled: "disabled", tipsRenderer: "tipsRenderer" }, outputs: { afterChange: "afterChange" }, providers: [SLIDER_CONTROL_VALUE_ACCESSOR], viewQueries: [{ propertyName: "slider", first: true, predicate: ["slider"], descendants: true, static: true }, { propertyName: "sliderHandle", first: true, predicate: ["sliderHandle"], descendants: true, static: true }, { propertyName: "sliderTrack", first: true, predicate: ["sliderTrack"], descendants: true, static: true }, { propertyName: "sliderRail", first: true, predicate: ["sliderRail"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"devui-slider\" #slider [ngClass]=\"{ disabled: disabled }\">\n  <div class=\"devui-slider-rail\" #sliderRail [ngClass]=\"{ disabled: disabled }\"></div>\n  <div class=\"devui-slider-track\" #sliderTrack [ngClass]=\"{ disabled: disabled }\"></div>\n  <div\n    class=\"devui-slider-handle\"\n    #sliderHandle\n    [ngClass]=\"{ disabled: disabled }\"\n    dPopover\n    position=\"top\"\n    [content]=\"showValuePopover && tipsRenderer ? tipsRenderer(value) : ''\"\n    [showAnimation]=\"false\"\n    [visible]=\"tipsRenderer && showValuePopover\"\n  ></div>\n</div>\n", styles: [":host{display:block}.devui-slider{position:relative;width:100%;padding:4px 0;margin:4px 0;cursor:pointer;box-sizing:border-box;height:14px;display:flex;align-items:center}.devui-slider .devui-slider-rail{position:absolute;background-color:#f5f5f5;background-color:var(--devui-area, #f5f5f5);height:5px;width:100%;transition:background-color .2s cubic-bezier(.645,.045,.355,1);transition:background-color var(--devui-animation-duration-base, .2s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(.645, .045, .355, 1));border-radius:100px;border-radius:var(--devui-border-radius-full, 100px)}.devui-slider .devui-slider-rail.disabled{background-color:#f5f5f5;background-color:var(--devui-area, #f5f5f5)}.devui-slider:hover .devui-slider-rail:not(.disabled){background-color:#f5f5f5;background-color:var(--devui-area, #f5f5f5)}.devui-slider:hover .devui-slider-track:not(.disabled){background-color:#7693f5;background-color:var(--devui-brand-hover, #7693f5)}.devui-slider:hover .devui-slider-handle:not(.disabled){border-color:#7693f5;border-color:var(--devui-brand-hover, #7693f5)}.devui-slider .devui-slider-track{position:absolute;background-color:#5e7ce0;background-color:var(--devui-brand, #5e7ce0);height:5px;width:0;border-radius:100px;border-radius:var(--devui-border-radius-full, 100px)}.devui-slider .devui-slider-handle{position:absolute;background-color:#fff;background-color:var(--devui-base-bg, #ffffff);width:14px;height:14px;border-radius:50%;left:0;transition:transform .2s ease-in-out;border:2px solid #5e7ce0;border:2px solid var(--devui-brand, #5e7ce0)}.devui-slider .devui-slider-handle:not(.disabled):hover,.devui-slider .devui-slider-handle:not(.disabled):active{transform:scale(1.3)}.devui-slider.disabled{cursor:not-allowed}.devui-slider.disabled .devui-slider-rail{background-color:#f5f5f5;background-color:var(--devui-disabled-bg, #f5f5f5)}.devui-slider.disabled .devui-slider-track{background-color:#dfe1e6;background-color:var(--devui-disabled-line, #dfe1e6)}.devui-slider.disabled .devui-slider-handle{border-color:#dfe1e6;border-color:var(--devui-disabled-line, #dfe1e6)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.PopoverDirective, selector: "[dPopover]", inputs: ["content", "controlled", "position", "showAnimation", "showAnimate", "scrollElement", "appendToBody", "zIndex", "popType", "popMaxWidth", "trigger", "hoverToContent", "hoverDelayTime", "popoverStyle", "mouseEnterDelay", "mouseLeaveDelay", "visible"], exportAs: ["dPopover"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: SliderComponent, decorators: [{
            type: Component,
            args: [{ selector: 'd-slider', providers: [SLIDER_CONTROL_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, preserveWhitespaces: false, template: "<div class=\"devui-slider\" #slider [ngClass]=\"{ disabled: disabled }\">\n  <div class=\"devui-slider-rail\" #sliderRail [ngClass]=\"{ disabled: disabled }\"></div>\n  <div class=\"devui-slider-track\" #sliderTrack [ngClass]=\"{ disabled: disabled }\"></div>\n  <div\n    class=\"devui-slider-handle\"\n    #sliderHandle\n    [ngClass]=\"{ disabled: disabled }\"\n    dPopover\n    position=\"top\"\n    [content]=\"showValuePopover && tipsRenderer ? tipsRenderer(value) : ''\"\n    [showAnimation]=\"false\"\n    [visible]=\"tipsRenderer && showValuePopover\"\n  ></div>\n</div>\n", styles: [":host{display:block}.devui-slider{position:relative;width:100%;padding:4px 0;margin:4px 0;cursor:pointer;box-sizing:border-box;height:14px;display:flex;align-items:center}.devui-slider .devui-slider-rail{position:absolute;background-color:#f5f5f5;background-color:var(--devui-area, #f5f5f5);height:5px;width:100%;transition:background-color .2s cubic-bezier(.645,.045,.355,1);transition:background-color var(--devui-animation-duration-base, .2s) var(--devui-animation-ease-in-out-smooth, cubic-bezier(.645, .045, .355, 1));border-radius:100px;border-radius:var(--devui-border-radius-full, 100px)}.devui-slider .devui-slider-rail.disabled{background-color:#f5f5f5;background-color:var(--devui-area, #f5f5f5)}.devui-slider:hover .devui-slider-rail:not(.disabled){background-color:#f5f5f5;background-color:var(--devui-area, #f5f5f5)}.devui-slider:hover .devui-slider-track:not(.disabled){background-color:#7693f5;background-color:var(--devui-brand-hover, #7693f5)}.devui-slider:hover .devui-slider-handle:not(.disabled){border-color:#7693f5;border-color:var(--devui-brand-hover, #7693f5)}.devui-slider .devui-slider-track{position:absolute;background-color:#5e7ce0;background-color:var(--devui-brand, #5e7ce0);height:5px;width:0;border-radius:100px;border-radius:var(--devui-border-radius-full, 100px)}.devui-slider .devui-slider-handle{position:absolute;background-color:#fff;background-color:var(--devui-base-bg, #ffffff);width:14px;height:14px;border-radius:50%;left:0;transition:transform .2s ease-in-out;border:2px solid #5e7ce0;border:2px solid var(--devui-brand, #5e7ce0)}.devui-slider .devui-slider-handle:not(.disabled):hover,.devui-slider .devui-slider-handle:not(.disabled):active{transform:scale(1.3)}.devui-slider.disabled{cursor:not-allowed}.devui-slider.disabled .devui-slider-rail{background-color:#f5f5f5;background-color:var(--devui-disabled-bg, #f5f5f5)}.devui-slider.disabled .devui-slider-track{background-color:#dfe1e6;background-color:var(--devui-disabled-line, #dfe1e6)}.devui-slider.disabled .devui-slider-handle{border-color:#dfe1e6;border-color:var(--devui-disabled-line, #dfe1e6)}\n"] }]
        }], ctorParameters: function () { return [{ type: i0.ChangeDetectorRef }]; }, propDecorators: { slider: [{
                type: ViewChild,
                args: ['slider', { static: true }]
            }], sliderHandle: [{
                type: ViewChild,
                args: ['sliderHandle', { static: true }]
            }], sliderTrack: [{
                type: ViewChild,
                args: ['sliderTrack', { static: true }]
            }], sliderRail: [{
                type: ViewChild,
                args: ['sliderRail', { static: true }]
            }], max: [{
                type: Input
            }], min: [{
                type: Input
            }], step: [{
                type: Input
            }], disabled: [{
                type: Input
            }], afterChange: [{
                type: Output
            }], tipsRenderer: [{
                type: Input
            }] } });

class SliderModule {
}
SliderModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: SliderModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
SliderModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.0", ngImport: i0, type: SliderModule, declarations: [SliderComponent], imports: [CommonModule,
        FormsModule,
        PopoverModule], exports: [SliderComponent] });
SliderModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: SliderModule, imports: [CommonModule,
        FormsModule,
        PopoverModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.0", ngImport: i0, type: SliderModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [
                        CommonModule,
                        FormsModule,
                        PopoverModule
                    ],
                    exports: [SliderComponent],
                    declarations: [SliderComponent],
                    providers: [],
                }]
        }] });

/**
 * Generated bundle index. Do not edit.
 */

export { SliderComponent, SliderModule };
//# sourceMappingURL=ng-devui-slider.mjs.map
