import * as i0 from '@angular/core';
import { model, input, numberAttribute, booleanAttribute, inject, ChangeDetectorRef, effect, ViewChildren, ViewChild, HostBinding, ChangeDetectionStrategy, Component } from '@angular/core';
import { NgControl } from '@angular/forms';
import * as i2 from '@angular/cdk/drag-drop';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { Subject, Subscription, fromEvent, takeUntil } from 'rxjs';
import * as i1 from '@eui/components/shared';
import { BaseStatesDirective } from '@eui/components/shared';
import { uniqueId } from '@eui/core';

/* eslint-disable @typescript-eslint/member-ordering */
/**
 * A draggable slider component for selecting numeric values within a defined range.
 * Supports both single-value and range selection modes with keyboard navigation,
 * visual feedback through tooltips and ticks, and full accessibility support.
 * Implements ControlValueAccessor for seamless integration with Angular forms.
 *
 * Use cases:
 * - Single value selection within a numeric range
 * - Range selection with start and end values
 * - Form-integrated numeric input with visual feedback
 * - Accessible numeric input for keyboard and screen reader users
 *
 * @usageNotes
 * ### Basic Usage
 * ```html
 * <!-- Single value slider -->
 * <eui-slider
 *   [min]="0"
 *   [max]="100"
 *   [step]="5"
 *   [(value)]="sliderValue" />
 *
 * <!-- Range slider -->
 * <eui-slider
 *   [min]="0"
 *   [max]="1000"
 *   [hasRange]="true"
 *   [hasTicks]="true"
 *   [(value)]="rangeValue" />
 *
 * <!-- With custom formatting -->
 * <eui-slider
 *   [formatValue]="formatPrice"
 *   [(value)]="price" />
 * ```
 *
 * ```typescript
 * sliderValue = { start: 50, end: null };
 * rangeValue = { start: 200, end: 800 };
 * formatPrice = (value: number) => `$${value}`;
 * ```
 *
 * ### Accessibility
 * - Keyboard navigation: Arrow keys to adjust, Home/End for min/max
 * - Provide descriptive ariaLabel for the slider purpose
 * - Use endAriaLabel for range sliders to distinguish handles
 * - Focus indicators show which handle is active
 *
 * ### Notes
 * - Value structure: { start: number, end?: number | null }
 * - Range mode requires hasRange="true" and both start/end values
 * - Ticks display at each step interval when hasTicks="true"
 * - Tooltip shows current value on hover when hasTooltip="true"
 */
class EuiSliderComponent {
    /**
     * @description
     * Computes and returns the CSS classes for the component based on its current state.
     *
     * @returns {string} Space-separated string of CSS class names
     */
    get cssClasses() {
        return [
            this.baseStatesDirective.getCssClasses('eui-slider'),
            this.isDisabled ? 'eui-slider--disabled' : '',
            this.control?.invalid ? 'eui-slider--invalid eui-slider--danger' : '',
        ]
            .join(' ')
            .trim();
    }
    constructor() {
        /**
         * Initial value used by the slider.
         * @defaultValue { start: 0, end: 0 }
         */
        this.value = model({ start: 0, end: 100 }, ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
        /**
         * The lowest value in the range of permitted values.
         *
         * @default 0
         */
        // eslint-disable-next-line @angular-eslint/no-input-rename
        this.minValue = input(0, { ...(ngDevMode ? { debugName: "minValue" } : /* istanbul ignore next */ {}), alias: 'min', transform: numberAttribute });
        /**
         * The greatest value in the range of permitted values.
         *
         * @default 100
         */
        // eslint-disable-next-line @angular-eslint/no-input-rename
        this.maxValue = input(100, { ...(ngDevMode ? { debugName: "maxValue" } : /* istanbul ignore next */ {}), alias: 'max', transform: numberAttribute });
        /**
         * Number that specifies the granularity that the value must adhere to.
         *
         * @default 1
         */
        this.step = input(1, { ...(ngDevMode ? { debugName: "step" } : /* istanbul ignore next */ {}), transform: numberAttribute });
        /**
         * Wheter a tooltip should be displayed when the handlers are hovered.
         *
         * @default true
         */
        this.hasTooltip = input(true, { ...(ngDevMode ? { debugName: "hasTooltip" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
        /**
         * Wheter a ticks should be displayed at each step interval.
         *
         * @default false
         */
        this.hasTicks = input(false, { ...(ngDevMode ? { debugName: "hasTicks" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
        /**
         * Wheter the value should be displayed on the top right of the track.
         *
         * @default true
         */
        this.hasValueIndicator = input(true, { ...(ngDevMode ? { debugName: "hasValueIndicator" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
        /**
         * Wheter a second should be display to allow to select a range.
         *
         * @default false
         */
        this.hasRange = input(false, { ...(ngDevMode ? { debugName: "hasRange" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
        /**
         * Method that allows to format the value display.
         *
         * @return The formatted string
         * @defaultValue (value: number) => `${value}`
         */
        this.formatValue = input((value) => `${value}`, ...(ngDevMode ? [{ debugName: "formatValue" }] : /* istanbul ignore next */ []));
        /**
         * @description
         * The label for the slider, used for accessibility.
         * @default 'eUI slider'.
         */
        this.ariaLabel = input('eUI slider', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
        /**
         * @description
         * The label for the end slider in case there is a range, used for accessibility.
         * @default 'end eUI slider'.
         */
        this.endAriaLabel = input('end eUI slider', ...(ngDevMode ? [{ debugName: "endAriaLabel" }] : /* istanbul ignore next */ []));
        /**
         * @description
         * The unique identifier for the slider.
         * This is used for accessibility and to link the slider with its label.
         * @default 'eui-slider-' + uniqueId()
         */
        this.sliderId = input(`eui-slider-${uniqueId()}`, ...(ngDevMode ? [{ debugName: "sliderId" }] : /* istanbul ignore next */ []));
        this.isDisabled = false;
        this.initValue = {
            start: { x: 0, y: 0 },
            end: { x: 0, y: 0 },
        };
        this.ticks = [];
        this.baseStatesDirective = inject(BaseStatesDirective);
        this.control = inject(NgControl, { self: true, optional: true });
        this.cd = inject(ChangeDetectorRef);
        this.destroy$ = new Subject();
        this.keyboardSubscription = new Subscription();
        /**
         * Position where the user clicked to start the drag of an handler
         */
        this.dragOffsetX = 0;
        /**
         * Constrains the position of a handler to the position of the other one.
         * Start handler cannot go after end handler. End handler cannot go before start handler.
         *
         * @param handlerId Dragged handler
         * @returns A function constraining the position.
         */
        this.constrainPosition = (handlerId) => {
            return (point) => {
                const containerRect = this.sliderContainer.nativeElement.getBoundingClientRect();
                let minX = 0;
                let maxX = containerRect.width + containerRect.left;
                if (handlerId === 'start' && this.endHandler?.nativeElement) {
                    const endRect = this.endHandler.nativeElement.getBoundingClientRect();
                    maxX = endRect.left;
                }
                else if (handlerId === 'end' && this.startHandler?.nativeElement) {
                    const startRect = this.startHandler.nativeElement.getBoundingClientRect();
                    minX = startRect.left;
                }
                const adjustedX = point.x - this.dragOffsetX;
                const x = Math.max(minX, Math.min(adjustedX, maxX));
                return {
                    x,
                    y: 0,
                };
            };
        };
        // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-empty-function
        this.onChange = () => { };
        // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-empty-function
        this.onTouched = () => { };
        if (this.control) {
            this.control.valueAccessor = this;
        }
        effect(() => {
            const v = this.value();
            queueMicrotask(() => this.onChange(v));
        });
    }
    ngOnInit() {
        if (this.value() === null) {
            this.value.set({ start: 0, end: 0 });
        }
        if (!this.hasRange()) {
            this.value.update(v => ({ ...v, end: null }));
        }
    }
    ngAfterViewInit() {
        this.inputRanges.toArray().forEach((inputRange) => {
            const handlerId = inputRange.nativeElement.classList.contains('range-input-start') ? 'start' : 'end';
            fromEvent(inputRange.nativeElement, 'focus').pipe(takeUntil(this.destroy$)).subscribe(() => {
                if (handlerId === 'start') {
                    this.startHandler.nativeElement.classList.add('eui-slider__handler--focused');
                }
                else {
                    this.endHandler.nativeElement.classList.add('eui-slider__handler--focused');
                }
                this.keyboardSubscription = fromEvent(inputRange.nativeElement, 'keydown').pipe(takeUntil(this.destroy$)).subscribe((event) => {
                    if (!this.isDisabled) {
                        if ((event.key) === 'Home') {
                            this.value.update(v => ({
                                ...v,
                                [handlerId]: this.hasRange() ? (handlerId === 'start' ? this.minValue() : v.start) : this.minValue(),
                            }));
                            this.setPositionValue(handlerId, this.value()[handlerId]);
                            event.preventDefault();
                        }
                        if ((event.key) === 'End') {
                            this.value.update(v => ({
                                ...v,
                                [handlerId]: this.hasRange() ? (handlerId === 'start' ? v.end : this.maxValue()) : this.maxValue(),
                            }));
                            this.setPositionValue(handlerId, this.value()[handlerId]);
                            event.preventDefault();
                        }
                        if ((event.key) === 'ArrowRight' || (event.key) === 'ArrowUp') {
                            this.value.update(v => {
                                const newValue = v[handlerId] + this.step();
                                const limit = this.hasRange() ? (handlerId === 'start' ? v.end : this.maxValue()) : this.maxValue();
                                return v[handlerId] < limit ? { ...v, [handlerId]: Math.min(newValue, limit) } : v;
                            });
                            this.setPositionValue(handlerId, this.value()[handlerId]);
                            event.preventDefault();
                        }
                        if ((event.key) === 'ArrowLeft' || (event.key) === 'ArrowDown') {
                            this.value.update(v => {
                                const newValue = v[handlerId] - this.step();
                                const limit = this.hasRange() ? (handlerId === 'start' ? this.minValue() : v.start) : this.minValue();
                                return v[handlerId] > limit ? { ...v, [handlerId]: Math.max(newValue, limit) } : v;
                            });
                            this.setPositionValue(handlerId, this.value()[handlerId]);
                            event.preventDefault();
                        }
                        this.cd.detectChanges();
                    }
                });
            });
            fromEvent(inputRange.nativeElement, 'blur').pipe(takeUntil(this.destroy$)).subscribe(() => {
                if (handlerId === 'start') {
                    this.startHandler.nativeElement.classList.remove('eui-slider__handler--focused');
                }
                else {
                    this.endHandler.nativeElement.classList.remove('eui-slider__handler--focused');
                }
                this.onTouched();
                this.keyboardSubscription.unsubscribe();
            });
        });
        this.handlers.toArray().forEach((handler) => {
            const handlerId = handler.nativeElement.classList.contains('eui-slider__handler-start') ? 'start' : 'end';
            fromEvent(handler.nativeElement, 'click').pipe(takeUntil(this.destroy$)).subscribe((event) => {
                if (handlerId === 'start') {
                    this.startInputRange.nativeElement.focus();
                }
                else {
                    this.endInputRange.nativeElement.focus();
                }
                event.stopPropagation();
            });
            fromEvent(handler.nativeElement, 'mousedown').pipe(takeUntil(this.destroy$)).subscribe((event) => {
                const rect = handler.nativeElement.getBoundingClientRect();
                this.dragOffsetX = event.clientX - rect.left;
                event.stopPropagation();
            });
        });
        this.resizeObserver = new ResizeObserver(() => {
            this.setPositionValue('start', this.value().start);
            if (this.hasRange()) {
                this.setPositionValue('end', this.value().end);
            }
            if (this.hasTicks()) {
                this.generateTicks();
            }
        });
        this.resizeObserver.observe(this.sliderContainer.nativeElement);
        if (this.hasTicks()) {
            this.generateTicks();
        }
    }
    ngOnDestroy() {
        this.destroy$.next(true);
        this.destroy$.unsubscribe();
        this.resizeObserver?.disconnect();
        this.keyboardSubscription?.unsubscribe();
    }
    get formattedStartValue() {
        return this.formatValue()(this.value().start);
    }
    get formattedEndValue() {
        return this.formatValue()(this.value().end);
    }
    /**
     * Drag handler
     *
     * @param handlerId Dragged handler
     * @param e Event
     */
    onDragMoved(handlerId, e) {
        e.source.element.nativeElement.classList.add('eui-slider__handler--dragging');
        const containerRect = this.sliderContainer.nativeElement.getBoundingClientRect();
        const containerWidth = containerRect.width;
        const handlerWidth = handlerId === 'start' ? this.startHandler.nativeElement.offsetWidth : this.endHandler.nativeElement.offsetWidth;
        const maxTravel = containerWidth - handlerWidth;
        const range = this.maxValue() - this.minValue();
        const pointerX = e.pointerPosition.x - containerRect.left;
        const ratio = Math.max(0, Math.min(1, pointerX / maxTravel));
        const rawValue = this.minValue() + (ratio * range);
        const steppedValue = (Math.round(((rawValue - this.minValue()) / this.step())) * this.step()) + this.minValue();
        const clampedValue = Math.max(this.minValue(), Math.min(this.maxValue(), steppedValue));
        this.value.update(v => ({ ...v, [handlerId]: clampedValue }));
        const finalRatio = (clampedValue - this.minValue()) / range;
        const snappedX = Math.round(finalRatio * maxTravel);
        this.initValue[handlerId] = { x: snappedX, y: 0 };
        this.calculateActiveTrack();
        this.onChange(this.value());
        this.onTouched();
    }
    /**
     * Drag end handler
     *
     * @param e
     */
    onDragEnded(e) {
        e.source.element.nativeElement.classList.remove('eui-slider__handler--dragging');
    }
    writeValue(value) {
        if (!value) {
            this.value.set({ start: 0, end: 0 });
        }
        else {
            this.value.set(value);
        }
        if (!this.hasRange()) {
            this.value.update(v => ({ ...v, end: null }));
        }
        Promise.resolve().then(() => {
            this.setPositionValue('start', this.value().start);
            if (this.hasRange()) {
                this.setPositionValue('end', this.value().end);
            }
        });
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    registerOnChange(fn) {
        this.onChange = fn;
    }
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    setDisabledState(isDisabled) {
        this.isDisabled = isDisabled;
        this.cd.detectChanges();
    }
    /**
     * Click on track handler
     *
     * @param e Click event
     */
    onTrackClick(e) {
        if (!this.isDisabled) {
            const containerRect = this.sliderContainer.nativeElement.getBoundingClientRect();
            const x = e.clientX - containerRect.left;
            const containerWidth = this.sliderContainer.nativeElement.offsetWidth;
            const range = this.maxValue() - this.minValue();
            const ratio = Math.max(0, Math.min(1, x / containerWidth));
            const rawValue = this.minValue() + (ratio * range);
            const steppedValue = (Math.round(((rawValue - this.minValue()) / this.step())) * this.step()) + this.minValue();
            const clampedValue = Math.max(this.minValue(), Math.min(this.maxValue(), steppedValue));
            if (this.hasRange()) {
                const distToStart = Math.abs(this.value().start - clampedValue);
                const distToEnd = Math.abs(this.value().end - clampedValue);
                let closest;
                if (distToStart === distToEnd) {
                    closest = clampedValue >= this.value().start ? 'end' : 'start';
                }
                else {
                    closest = distToStart < distToEnd ? 'start' : 'end';
                }
                // this.value()[closest] = clampedValue;
                this.value.update(v => ({ ...v, [closest]: clampedValue }));
                this.setPositionValue(closest, clampedValue);
            }
            else {
                // this.value().start = clampedValue;
                this.value.update(v => ({ ...v, start: clampedValue }));
                this.setPositionValue('start', clampedValue);
            }
            this.onChange(this.value());
            this.onTouched();
        }
    }
    /**
     * Calculates the positon of an handler for a given value.
     *
     * @param handlerId Handler to position
     * @param value Value on which calculate the position
     */
    setPositionValue(handlerId, value) {
        const container = this.sliderContainer.nativeElement;
        const handler = handlerId === 'start' ? this.startHandler.nativeElement : this.endHandler.nativeElement;
        const containerWidth = container.offsetWidth;
        const handlerWidth = handler.offsetWidth;
        const maxTravel = containerWidth - handlerWidth;
        const range = this.maxValue() - this.minValue();
        const clamped = Math.max(this.minValue(), Math.min(this.maxValue(), value));
        const ratio = (clamped - this.minValue()) / range;
        const x = Math.round(ratio * maxTravel);
        this.initValue[handlerId] = { x, y: 0 };
        this.cd.detectChanges();
        this.calculateActiveTrack();
    }
    /**
     * Calculate the size of the active track between two handlers
     */
    calculateActiveTrack() {
        const startX = this.initValue.start ? this.initValue.start.x : 0;
        const endX = this.hasRange() ? this.initValue.end.x : startX;
        const track = this.trackActive.nativeElement;
        if (this.hasRange()) {
            const left = Math.min(startX, endX);
            const width = Math.abs(endX - startX);
            track.style.left = `${left}px`;
            track.style.width = `${width}px`;
        }
        else {
            track.style.left = '0px';
            track.style.width = `${startX}px`;
        }
    }
    /**
     * Generates the ticks based on the step option.
     */
    generateTicks() {
        const stepCount = Math.floor((this.maxValue() - this.minValue()) / this.step());
        const containerWidth = this.sliderContainer.nativeElement.offsetWidth;
        const handlerWidth = this.startHandler.nativeElement.offsetWidth;
        const maxTravel = containerWidth - handlerWidth;
        this.ticks = [];
        for (let i = 0; i <= stepCount; i++) {
            const val = this.minValue() + (i * this.step());
            const ratio = (val - this.minValue()) / (this.maxValue() - this.minValue());
            const px = ((ratio * maxTravel) + handlerWidth / 2).toFixed(1);
            this.ticks.push({ value: val, position: `${px}px` });
        }
        this.cd.detectChanges();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.16", type: EuiSliderComponent, isStandalone: true, selector: "eui-slider", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, minValue: { classPropertyName: "minValue", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, maxValue: { classPropertyName: "maxValue", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, hasTooltip: { classPropertyName: "hasTooltip", publicName: "hasTooltip", isSignal: true, isRequired: false, transformFunction: null }, hasTicks: { classPropertyName: "hasTicks", publicName: "hasTicks", isSignal: true, isRequired: false, transformFunction: null }, hasValueIndicator: { classPropertyName: "hasValueIndicator", publicName: "hasValueIndicator", isSignal: true, isRequired: false, transformFunction: null }, hasRange: { classPropertyName: "hasRange", publicName: "hasRange", isSignal: true, isRequired: false, transformFunction: null }, formatValue: { classPropertyName: "formatValue", publicName: "formatValue", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, endAriaLabel: { classPropertyName: "endAriaLabel", publicName: "endAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, sliderId: { classPropertyName: "sliderId", publicName: "sliderId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, host: { properties: { "class": "this.cssClasses" } }, viewQueries: [{ propertyName: "sliderContainer", first: true, predicate: ["sliderContainer"], descendants: true, static: true }, { propertyName: "trackActive", first: true, predicate: ["trackActive"], descendants: true }, { propertyName: "startHandler", first: true, predicate: ["startHandler"], descendants: true }, { propertyName: "startHandlerContainer", first: true, predicate: ["startHandlerContainer"], descendants: true }, { propertyName: "endHandler", first: true, predicate: ["endHandler"], descendants: true }, { propertyName: "endHandlerContainer", first: true, predicate: ["endHandlerContainer"], descendants: true }, { propertyName: "startInputRange", first: true, predicate: ["startInputRange"], descendants: true }, { propertyName: "endInputRange", first: true, predicate: ["endInputRange"], descendants: true }, { propertyName: "handlers", predicate: ["handler"], descendants: true }, { propertyName: "inputRanges", predicate: ["inputRange"], descendants: true }], hostDirectives: [{ directive: i1.BaseStatesDirective, inputs: ["euiPrimary", "euiPrimary", "euiDanger", "euiDanger", "euiVariant", "euiVariant"] }], ngImport: i0, template: "@if (hasValueIndicator()) {\n    <div class=\"value-display\">\n        <span class=\"value-start\">{{ formattedStartValue }}</span>\n        @if (value().end !== null && value().end !== undefined) {\n            - <span class=\"value-end\">{{ formattedEndValue }}</span>\n        }\n    </div>\n}\n\n<div #sliderContainer class=\"eui-slider__container eui-u-flex\" (mousedown)=\"onTrackClick($event)\">\n    <input\n        [id]=\"sliderId()\"\n        #startInputRange \n        #inputRange \n        type=\"range\" \n        class=\"range-input range-input-start\"\n        [min]=\"minValue()\" \n        [max]=\"hasRange() ? value().end : maxValue()\" \n        [step]=\"step()\" \n        [value]=\"value().start\"\n        [attr.aria-valuenow]=\"value().start\"\n        [attr.aria-valuemin]=\"minValue()\"\n        [attr.aria-valuemax]=\"hasRange() ? value().end : maxValue()\" \n        role=\"slider\"\n        [attr.aria-label]=\"ariaLabel()\"\n        [attr.aria-valuetext]=\"formattedStartValue\"\n        list=\"markers\" />\n\n    <div\n        #startHandler\n        #handler\n        class=\"eui-slider__handler eui-slider__handler-start\"\n        [class.eui-slider__handler-start--max-reached]=\"hasRange() ? value().start === value().end && value().end === maxValue() : value().start === maxValue()\"\n        cdkDragBoundary=\".eui-slider__container\"\n        cdkDrag\n        [cdkDragConstrainPosition]=\"constrainPosition('start')\"\n        [cdkDragFreeDragPosition]=\"initValue.start\"\n        [cdkDragDisabled]=\"isDisabled\"\n        (cdkDragMoved)=\"onDragMoved('start', $event)\"\n        (cdkDragEnded)=\"onDragEnded($event)\">\n        @if (hasTooltip() && !isDisabled) {\n            <div class=\"value-indicator\">\n                {{ formattedStartValue }}\n            </div>\n        }\n    </div>\n\n    @if (hasRange() && value().end !== null && value().end !== undefined) {\n        <input\n            [id]=\"'end-' + sliderId()\"\n            #endInputRange\n            #inputRange\n            type=\"range\"\n            class=\"range-input range-input-end\"\n            [min]=\"value().start\"\n            [max]=\"maxValue()\"\n            [step]=\"step()\"\n            [value]=\"value().end\"\n            [attr.aria-valuenow]=\"value().end\"\n            [attr.aria-valuemin]=\"value().start\"\n            [attr.aria-valuemax]=\"maxValue()\"\n            role=\"slider\"\n            [attr.aria-label]=\"endAriaLabel()\"\n            [attr.aria-valuetext]=\"formattedEndValue\"\n            list=\"markers\" />\n        \n        <div\n            #endHandler\n            #handler\n            class=\"eui-slider__handler eui-slider__handler-end\"\n            [class.eui-slider__handler-end--min-reached]=\"value().end === value().start && value().start === minValue()\"\n            cdkDragBoundary=\".eui-slider__container\"\n            cdkDrag\n            [cdkDragConstrainPosition]=\"constrainPosition('end')\"\n            [cdkDragFreeDragPosition]=\"initValue.end\"\n            [cdkDragDisabled]=\"isDisabled\"\n            (cdkDragMoved)=\"onDragMoved('end', $event)\"\n            (cdkDragEnded)=\"onDragEnded($event)\">\n            @if (hasTooltip() && !isDisabled) {\n                <div class=\"value-indicator\">\n                    {{ formattedEndValue }}\n                </div>\n            }\n        </div>\n    }\n\n    <div class=\"eui-slider__track\">\n        <div #trackActive class=\"eui-slider__track--active\"></div>\n    </div>\n\n    @if (hasTicks()) {\n        <datalist id=\"markers\">\n            @for (tick of ticks; track tick.value) {\n                <option [value]=\"tick.value\"></option>\n            }\n        </datalist>\n    \n        <div class=\"eui-slider__ticks\">\n            @for (tick of ticks; track tick.value) {\n                <span class=\"tick\" [style.left]=\"tick.position\"></span>\n            }\n        </div>\n    }\n</div>\n", styles: [".eui-21 :host.eui-slider{--_bg-color: var(--eui-c-primary-surface);--_track-bg-color: var(--eui-c-primary-surface-light);--_track-cursor: pointer;--_handler-border-display: block;--_ticks-bg-color: var(--eui-c-primary-surface-medium)}.eui-21 :host.eui-slider--disabled{--_bg-color: var(--eui-c-disabled);--_track-bg-color: var(--eui-c-secondary-surface-light);--_track-cursor: default;--_handler-border-display: none;--_ticks-bg-color: var(--eui-c-secondary-surface-light)}.eui-21 :host.eui-slider--primary{--_bg-color: var(--eui-c-primary-surface);--_track-bg-color: var(--eui-c-primary-surface-light);--_ticks-bg-color: var(--eui-c-primary-surface-medium)}.eui-21 :host.eui-slider--danger{--_bg-color: var(--eui-c-danger-surface);--_track-bg-color: var(--eui-c-danger-surface-light);--_ticks-bg-color: var(--eui-c-danger-surface-medium)}.eui-21 :host.eui-slider--invalid{--_bg-color: var(--eui-c-danger-surface);--_track-bg-color: var(--eui-c-danger-surface-light);--_ticks-bg-color: var(--eui-c-danger-surface-medium)}.eui-21 :host.eui-slider{width:100%}.eui-21 :host.eui-slider .range-input{opacity:0;pointer-events:none;position:absolute}.eui-21 :host.eui-slider .value-display{line-height:normal;text-align:right}.eui-21 :host.eui-slider .eui-slider__container{cursor:var(--_track-cursor);height:var(--eui-s-l);position:relative}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__track{align-items:center;background-color:var(--_track-bg-color);height:var(--eui-s-4xs);width:100%;position:relative;z-index:2}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__track--active{background-color:var(--_bg-color);height:var(--eui-s-4xs);position:absolute}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler{border:0;width:var(--eui-s-l);height:var(--eui-s-l);border-radius:100px;background-color:var(--_bg-color);position:absolute;cursor:var(--_track-cursor);outline:none;display:flex;justify-content:center}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler-start{z-index:8}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler-start--max-reached{z-index:9}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler-end{z-index:8}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler-end--min-reached{z-index:9}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler .value-indicator{position:absolute;top:-3rem;background-color:var(--eui-c-secondary);border-radius:var(--eui-br-s);box-shadow:var(--eui-sh-1);color:var(--eui-c-white);letter-spacing:.05em;max-width:50vw;padding:var(--eui-s-xs);white-space:pre-line;font:var(--eui-f-xs);display:none;text-wrap:nowrap}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler .value-indicator:before{border-color:var(--eui-c-secondary) transparent transparent transparent;border-style:solid;border-width:8px;bottom:2px;content:\"\";display:block;height:0;position:absolute;width:0;left:calc(50% - 8px);transform:translateY(16px)}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler:hover .value-indicator,.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler--dragging .value-indicator,.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler--focused .value-indicator{display:block}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler:hover:after,.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler--dragging:after,.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler--focused:after{content:\"\";position:absolute;display:var(--_handler-border-display);inset:-2px;border:1px solid var(--_bg-color);border-radius:100px;pointer-events:none}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__ticks{position:absolute;top:60%;left:0;width:100%;height:100%;pointer-events:none;transform:translateY(-50%);z-index:1}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__ticks .tick{position:absolute;width:var(--eui-s-4xs);height:var(--eui-s-xs);background-color:var(--_ticks-bg-color);transform:translate(-50%)}\n"], dependencies: [{ kind: "ngmodule", type: DragDropModule }, { kind: "directive", type: i2.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.16", ngImport: i0, type: EuiSliderComponent, decorators: [{
            type: Component,
            args: [{ selector: 'eui-slider', changeDetection: ChangeDetectionStrategy.OnPush, hostDirectives: [
                        {
                            directive: BaseStatesDirective,
                            inputs: ['euiPrimary', 'euiDanger', 'euiVariant'],
                        },
                    ], imports: [DragDropModule], template: "@if (hasValueIndicator()) {\n    <div class=\"value-display\">\n        <span class=\"value-start\">{{ formattedStartValue }}</span>\n        @if (value().end !== null && value().end !== undefined) {\n            - <span class=\"value-end\">{{ formattedEndValue }}</span>\n        }\n    </div>\n}\n\n<div #sliderContainer class=\"eui-slider__container eui-u-flex\" (mousedown)=\"onTrackClick($event)\">\n    <input\n        [id]=\"sliderId()\"\n        #startInputRange \n        #inputRange \n        type=\"range\" \n        class=\"range-input range-input-start\"\n        [min]=\"minValue()\" \n        [max]=\"hasRange() ? value().end : maxValue()\" \n        [step]=\"step()\" \n        [value]=\"value().start\"\n        [attr.aria-valuenow]=\"value().start\"\n        [attr.aria-valuemin]=\"minValue()\"\n        [attr.aria-valuemax]=\"hasRange() ? value().end : maxValue()\" \n        role=\"slider\"\n        [attr.aria-label]=\"ariaLabel()\"\n        [attr.aria-valuetext]=\"formattedStartValue\"\n        list=\"markers\" />\n\n    <div\n        #startHandler\n        #handler\n        class=\"eui-slider__handler eui-slider__handler-start\"\n        [class.eui-slider__handler-start--max-reached]=\"hasRange() ? value().start === value().end && value().end === maxValue() : value().start === maxValue()\"\n        cdkDragBoundary=\".eui-slider__container\"\n        cdkDrag\n        [cdkDragConstrainPosition]=\"constrainPosition('start')\"\n        [cdkDragFreeDragPosition]=\"initValue.start\"\n        [cdkDragDisabled]=\"isDisabled\"\n        (cdkDragMoved)=\"onDragMoved('start', $event)\"\n        (cdkDragEnded)=\"onDragEnded($event)\">\n        @if (hasTooltip() && !isDisabled) {\n            <div class=\"value-indicator\">\n                {{ formattedStartValue }}\n            </div>\n        }\n    </div>\n\n    @if (hasRange() && value().end !== null && value().end !== undefined) {\n        <input\n            [id]=\"'end-' + sliderId()\"\n            #endInputRange\n            #inputRange\n            type=\"range\"\n            class=\"range-input range-input-end\"\n            [min]=\"value().start\"\n            [max]=\"maxValue()\"\n            [step]=\"step()\"\n            [value]=\"value().end\"\n            [attr.aria-valuenow]=\"value().end\"\n            [attr.aria-valuemin]=\"value().start\"\n            [attr.aria-valuemax]=\"maxValue()\"\n            role=\"slider\"\n            [attr.aria-label]=\"endAriaLabel()\"\n            [attr.aria-valuetext]=\"formattedEndValue\"\n            list=\"markers\" />\n        \n        <div\n            #endHandler\n            #handler\n            class=\"eui-slider__handler eui-slider__handler-end\"\n            [class.eui-slider__handler-end--min-reached]=\"value().end === value().start && value().start === minValue()\"\n            cdkDragBoundary=\".eui-slider__container\"\n            cdkDrag\n            [cdkDragConstrainPosition]=\"constrainPosition('end')\"\n            [cdkDragFreeDragPosition]=\"initValue.end\"\n            [cdkDragDisabled]=\"isDisabled\"\n            (cdkDragMoved)=\"onDragMoved('end', $event)\"\n            (cdkDragEnded)=\"onDragEnded($event)\">\n            @if (hasTooltip() && !isDisabled) {\n                <div class=\"value-indicator\">\n                    {{ formattedEndValue }}\n                </div>\n            }\n        </div>\n    }\n\n    <div class=\"eui-slider__track\">\n        <div #trackActive class=\"eui-slider__track--active\"></div>\n    </div>\n\n    @if (hasTicks()) {\n        <datalist id=\"markers\">\n            @for (tick of ticks; track tick.value) {\n                <option [value]=\"tick.value\"></option>\n            }\n        </datalist>\n    \n        <div class=\"eui-slider__ticks\">\n            @for (tick of ticks; track tick.value) {\n                <span class=\"tick\" [style.left]=\"tick.position\"></span>\n            }\n        </div>\n    }\n</div>\n", styles: [".eui-21 :host.eui-slider{--_bg-color: var(--eui-c-primary-surface);--_track-bg-color: var(--eui-c-primary-surface-light);--_track-cursor: pointer;--_handler-border-display: block;--_ticks-bg-color: var(--eui-c-primary-surface-medium)}.eui-21 :host.eui-slider--disabled{--_bg-color: var(--eui-c-disabled);--_track-bg-color: var(--eui-c-secondary-surface-light);--_track-cursor: default;--_handler-border-display: none;--_ticks-bg-color: var(--eui-c-secondary-surface-light)}.eui-21 :host.eui-slider--primary{--_bg-color: var(--eui-c-primary-surface);--_track-bg-color: var(--eui-c-primary-surface-light);--_ticks-bg-color: var(--eui-c-primary-surface-medium)}.eui-21 :host.eui-slider--danger{--_bg-color: var(--eui-c-danger-surface);--_track-bg-color: var(--eui-c-danger-surface-light);--_ticks-bg-color: var(--eui-c-danger-surface-medium)}.eui-21 :host.eui-slider--invalid{--_bg-color: var(--eui-c-danger-surface);--_track-bg-color: var(--eui-c-danger-surface-light);--_ticks-bg-color: var(--eui-c-danger-surface-medium)}.eui-21 :host.eui-slider{width:100%}.eui-21 :host.eui-slider .range-input{opacity:0;pointer-events:none;position:absolute}.eui-21 :host.eui-slider .value-display{line-height:normal;text-align:right}.eui-21 :host.eui-slider .eui-slider__container{cursor:var(--_track-cursor);height:var(--eui-s-l);position:relative}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__track{align-items:center;background-color:var(--_track-bg-color);height:var(--eui-s-4xs);width:100%;position:relative;z-index:2}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__track--active{background-color:var(--_bg-color);height:var(--eui-s-4xs);position:absolute}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler{border:0;width:var(--eui-s-l);height:var(--eui-s-l);border-radius:100px;background-color:var(--_bg-color);position:absolute;cursor:var(--_track-cursor);outline:none;display:flex;justify-content:center}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler-start{z-index:8}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler-start--max-reached{z-index:9}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler-end{z-index:8}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler-end--min-reached{z-index:9}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler .value-indicator{position:absolute;top:-3rem;background-color:var(--eui-c-secondary);border-radius:var(--eui-br-s);box-shadow:var(--eui-sh-1);color:var(--eui-c-white);letter-spacing:.05em;max-width:50vw;padding:var(--eui-s-xs);white-space:pre-line;font:var(--eui-f-xs);display:none;text-wrap:nowrap}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler .value-indicator:before{border-color:var(--eui-c-secondary) transparent transparent transparent;border-style:solid;border-width:8px;bottom:2px;content:\"\";display:block;height:0;position:absolute;width:0;left:calc(50% - 8px);transform:translateY(16px)}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler:hover .value-indicator,.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler--dragging .value-indicator,.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler--focused .value-indicator{display:block}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler:hover:after,.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler--dragging:after,.eui-21 :host.eui-slider .eui-slider__container .eui-slider__handler--focused:after{content:\"\";position:absolute;display:var(--_handler-border-display);inset:-2px;border:1px solid var(--_bg-color);border-radius:100px;pointer-events:none}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__ticks{position:absolute;top:60%;left:0;width:100%;height:100%;pointer-events:none;transform:translateY(-50%);z-index:1}.eui-21 :host.eui-slider .eui-slider__container .eui-slider__ticks .tick{position:absolute;width:var(--eui-s-4xs);height:var(--eui-s-xs);background-color:var(--_ticks-bg-color);transform:translate(-50%)}\n"] }]
        }], ctorParameters: () => [], propDecorators: { cssClasses: [{
                type: HostBinding,
                args: ['class']
            }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], minValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], maxValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], hasTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasTooltip", required: false }] }], hasTicks: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasTicks", required: false }] }], hasValueIndicator: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasValueIndicator", required: false }] }], hasRange: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasRange", required: false }] }], formatValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "formatValue", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], endAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "endAriaLabel", required: false }] }], sliderId: [{ type: i0.Input, args: [{ isSignal: true, alias: "sliderId", required: false }] }], sliderContainer: [{
                type: ViewChild,
                args: ['sliderContainer', { static: true }]
            }], trackActive: [{
                type: ViewChild,
                args: ['trackActive', { static: false }]
            }], startHandler: [{
                type: ViewChild,
                args: ['startHandler', { static: false }]
            }], startHandlerContainer: [{
                type: ViewChild,
                args: ['startHandlerContainer', { static: false }]
            }], endHandler: [{
                type: ViewChild,
                args: ['endHandler', { static: false }]
            }], endHandlerContainer: [{
                type: ViewChild,
                args: ['endHandlerContainer', { static: false }]
            }], handlers: [{
                type: ViewChildren,
                args: ['handler']
            }], startInputRange: [{
                type: ViewChild,
                args: ['startInputRange', { static: false }]
            }], endInputRange: [{
                type: ViewChild,
                args: ['endInputRange', { static: false }]
            }], inputRanges: [{
                type: ViewChildren,
                args: ['inputRange']
            }] } });

/**
 * @description
 * Validator that requires the min / max of start and / or end values.
 *
 * @usageNotes
 * ```typescript
 * const slider = new FormControl<IEuiSliderValues>({ start: 10, end: 50 }, [sliderValidator({ startMin: 5, startMax: 50, endMin: 30, endMax: 90 })]),
 * console.log(slider.errors); // null
 *
 * const slider = new FormControl<IEuiSliderValues>({ start: 0, end: 50 }, [sliderValidator({ startMin: 5, startMax: 50, endMin: 30, endMax: 90 })]),
 * console.log(slider.errors); // { startMin: { required: 5, actual: 0 } }
 *
 * const slider = new FormControl<IEuiSliderValues>({ start: 60, end: 80 }, [sliderValidator({ startMin: 5, startMax: 50, endMin: 30, endMax: 90 })]),
 * console.log(slider.errors); // { startMax: { required: 50, actual: 60 } }
 *
 * const slider = new FormControl<IEuiSliderValues>({ start: 10, end: 20 }, [sliderValidator({ startMin: 5, startMax: 50, endMin: 30, endMax: 90 })]),
 * console.log(slider.errors); // { endMin: { required: 30, actual: 20 } }
 *
 * const slider = new FormControl<IEuiSliderValues>({ start: 10, end: 100 }, [sliderValidator({ startMin: 5, startMax: 50, endMin: 30, endMax: 90 })]),
 * console.log(slider.errors); // { endMax: { required: 90, actual: 100 } }
 * ```
 *
 * @returns A validator function that returns an error map with `startMin` /  `startMax` /  `endMin` /  `endMax` if the validation check fails, otherwise `null`.
 */
function sliderValidator(config) {
    return (control) => {
        const value = control.value;
        if (!value)
            return null;
        const errors = {};
        if (config.startMin !== undefined && value.start < config.startMin) {
            errors.startMin = {
                required: config.startMin,
                actual: value.start,
            };
        }
        if (config.startMax !== undefined && value.start > config.startMax) {
            errors.startMax = {
                required: config.startMax,
                actual: value.start,
            };
        }
        if (value.end != null) {
            if (config.endMin !== undefined && value.end < config.endMin) {
                errors.endMin = {
                    required: config.endMin,
                    actual: value.end,
                };
            }
            if (config.endMax !== undefined && value.end > config.endMax) {
                errors.endMax = {
                    required: config.endMax,
                    actual: value.end,
                };
            }
        }
        return Object.keys(errors).length > 0 ? errors : null;
    };
}

const EUI_SLIDER = [
    EuiSliderComponent,
];

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

export { EUI_SLIDER, EuiSliderComponent, sliderValidator };
//# sourceMappingURL=eui-components-eui-slider.mjs.map
