import * as i0 from '@angular/core';
import { inject, PLATFORM_ID, NgZone, DestroyRef, viewChild, input, signal, computed, effect, Component, Directive } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
import { Icon } from '@ngstarter-ui/components/icon';
import { fromEvent, merge, takeUntil } from 'rxjs';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';

class ComparisonSlider {
    resizeObserver = null;
    platformId = inject(PLATFORM_ID);
    ngZone = inject(NgZone);
    destroyRef = inject(DestroyRef);
    sliderContainerRef = viewChild.required('sliderContainer');
    handleRef = viewChild.required('handle');
    initialPosition = input(50, ...(ngDevMode ? [{ debugName: "initialPosition" }] : /* istanbul ignore next */ []));
    sliderPosition = signal(0, ...(ngDevMode ? [{ debugName: "sliderPosition" }] : /* istanbul ignore next */ []));
    isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
    containerRect = null;
    handleLeftStyle = computed(() => `${this.sliderPosition()}%`, ...(ngDevMode ? [{ debugName: "handleLeftStyle" }] : /* istanbul ignore next */ []));
    afterImageClipStyle = computed(() => `inset(0 ${100 - this.sliderPosition()}% 0 0)`, ...(ngDevMode ? [{ debugName: "afterImageClipStyle" }] : /* istanbul ignore next */ []));
    isBrowser;
    constructor() {
        this.isBrowser = isPlatformBrowser(this.platformId);
        effect(() => {
            const initial = this.initialPosition();
            this.sliderPosition.set(Math.max(0, Math.min(100, initial)));
        });
    }
    ngAfterViewInit() {
        if (this.isBrowser) {
            this.updateContainerRect();
            if (typeof ResizeObserver !== 'undefined' && this.sliderContainerRef() && this.sliderContainerRef().nativeElement) {
                this.resizeObserver = new ResizeObserver(() => {
                    this.updateContainerRect();
                });
                this.resizeObserver.observe(this.sliderContainerRef().nativeElement);
            }
            this.initDragStreams();
        }
    }
    initDragStreams() {
        const container = this.sliderContainerRef().nativeElement;
        const handle = this.handleRef().nativeElement;
        this.ngZone.runOutsideAngular(() => {
            const mouseDown$ = fromEvent(handle, 'mousedown');
            const touchStart$ = fromEvent(handle, 'touchstart');
            const containerMouseDown$ = fromEvent(container, 'mousedown');
            const containerTouchStart$ = fromEvent(container, 'touchstart');
            const mouseMove$ = fromEvent(window, 'mousemove');
            const touchMove$ = fromEvent(window, 'touchmove', { passive: false });
            const mouseUp$ = fromEvent(window, 'mouseup');
            const touchEnd$ = fromEvent(window, 'touchend');
            const start$ = merge(mouseDown$, touchStart$);
            const move$ = merge(mouseMove$, touchMove$);
            const end$ = merge(mouseUp$, touchEnd$);
            merge(start$, containerMouseDown$, containerTouchStart$)
                .pipe(takeUntilDestroyed(this.destroyRef))
                .subscribe((event) => {
                if (event instanceof MouseEvent && event.button !== 0) {
                    return;
                }
                if (event.currentTarget === container && handle.contains(event.target)) {
                    return;
                }
                this.ngZone.run(() => {
                    this.isDragging.set(true);
                    this.updateContainerRect();
                    const clientX = event instanceof MouseEvent ? event.clientX : (event.touches.length > 0 ? event.touches[0].clientX : 0);
                    this.updateSliderPosition(clientX);
                });
                const moveSubscription = move$
                    .pipe(takeUntil(end$))
                    .subscribe((moveEvent) => {
                    if (moveEvent.cancelable) {
                        moveEvent.preventDefault();
                    }
                    const clientX = moveEvent instanceof MouseEvent ? moveEvent.clientX : (moveEvent.touches.length > 0 ? moveEvent.touches[0].clientX : 0);
                    this.ngZone.run(() => {
                        this.updateSliderPosition(clientX);
                    });
                });
                const endSubscription = end$
                    .pipe(takeUntil(start$))
                    .subscribe(() => {
                    moveSubscription.unsubscribe();
                    endSubscription.unsubscribe();
                    this.ngZone.run(() => {
                        this.isDragging.set(false);
                    });
                });
            });
        });
    }
    ngOnDestroy() {
        if (this.resizeObserver) {
            this.resizeObserver.disconnect();
        }
    }
    updateContainerRect() {
        if (this.isBrowser && this.sliderContainerRef()) {
            this.containerRect = this.sliderContainerRef().nativeElement.getBoundingClientRect();
        }
        else {
            this.containerRect = null;
        }
    }
    updateSliderPosition(clientX) {
        const rect = this.containerRect;
        if (!rect) {
            return;
        }
        const x = clientX - rect.left;
        let percentage = (x / rect.width) * 100;
        percentage = Math.max(0, Math.min(100, percentage));
        this.sliderPosition.set(percentage);
    }
    onContextMenu(event) {
        event.preventDefault();
    }
    onDragStart(event) {
        event.preventDefault();
        event.stopPropagation();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComparisonSlider, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.4", type: ComparisonSlider, isStandalone: true, selector: "ngs-comparison-slider", inputs: { initialPosition: { classPropertyName: "initialPosition", publicName: "initialPosition", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "contextmenu": "onContextMenu($event)", "dragstart": "onDragStart($event)" }, classAttribute: "ngs-comparison-slider not-prose" }, viewQueries: [{ propertyName: "sliderContainerRef", first: true, predicate: ["sliderContainer"], descendants: true, isSignal: true }, { propertyName: "handleRef", first: true, predicate: ["handle"], descendants: true, isSignal: true }], exportAs: ["ngsComparisonSlider"], ngImport: i0, template: "<div\n  #sliderContainer\n  class=\"comparison-slider-container\">\n  <div class=\"image-wrapper before-image-slot\">\n    <ng-content select=\"[ngsComparisonSliderBeforeImage]\"/>\n  </div>\n  <div class=\"image-wrapper after-image-slot\" [style.clipPath]=\"afterImageClipStyle()\">\n    <ng-content select=\"[ngsComparisonSliderAfterImage]\"/>\n  </div>\n  <div\n    #handle\n    class=\"slider-handle\"\n    [style.left]=\"handleLeftStyle()\"\n    role=\"slider\"\n    aria-orientation=\"horizontal\"\n    [attr.aria-valuenow]=\"sliderPosition()\"\n    aria-valuemin=\"0\"\n    aria-valuemax=\"100\"\n    [attr.aria-label]=\"'Image comparison slider control'\">\n    <div class=\"handle-line\"></div>\n    <div class=\"handle-grip\">\n      <ngs-icon name=\"fluent:chevron-left-24-regular\"/>\n      <ngs-icon name=\"fluent:chevron-right-24-regular\"/>\n    </div>\n  </div>\n</div>\n", styles: [":host{display:block;position:relative;overflow:hidden;width:100%;-webkit-user-select:none;user-select:none}:host .comparison-slider-container{position:relative;width:100%;height:100%;overflow:hidden;cursor:default}:host .image-wrapper{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden}:host .image-wrapper>::slotted(*){display:block;width:100%;height:100%;object-fit:cover}:host .before-image-slot{z-index:1}:host .after-image-slot{z-index:2}:host .slider-handle{position:absolute;top:0;bottom:0;width:40px;transform:translate(-50%);cursor:ew-resize;display:flex;align-items:center;justify-content:center;z-index:10}:host .slider-handle .handle-line{position:absolute;top:0;bottom:0;left:50%;transform:translate(-50%);width:4px;background:#fff;pointer-events:none}:host .slider-handle .handle-line:before{content:\"\";position:absolute;top:0;bottom:0;left:0;width:1px;background:#000}:host .slider-handle .handle-line:after{content:\"\";position:absolute;top:0;bottom:0;right:0;width:1px;background:#000}:host .slider-handle .handle-grip{height:36px;display:flex;align-items:center;justify-content:center;z-index:1;pointer-events:none;gap:calc(var(--spacing, .25rem) * 3)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"], dependencies: [{ kind: "component", type: Icon, selector: "ngs-icon", inputs: ["name"], exportAs: ["ngsIcon"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComparisonSlider, decorators: [{
            type: Component,
            args: [{ selector: 'ngs-comparison-slider', exportAs: 'ngsComparisonSlider', imports: [
                        Icon,
                    ], host: {
                        'class': 'ngs-comparison-slider not-prose',
                        '(contextmenu)': 'onContextMenu($event)',
                        '(dragstart)': 'onDragStart($event)'
                    }, template: "<div\n  #sliderContainer\n  class=\"comparison-slider-container\">\n  <div class=\"image-wrapper before-image-slot\">\n    <ng-content select=\"[ngsComparisonSliderBeforeImage]\"/>\n  </div>\n  <div class=\"image-wrapper after-image-slot\" [style.clipPath]=\"afterImageClipStyle()\">\n    <ng-content select=\"[ngsComparisonSliderAfterImage]\"/>\n  </div>\n  <div\n    #handle\n    class=\"slider-handle\"\n    [style.left]=\"handleLeftStyle()\"\n    role=\"slider\"\n    aria-orientation=\"horizontal\"\n    [attr.aria-valuenow]=\"sliderPosition()\"\n    aria-valuemin=\"0\"\n    aria-valuemax=\"100\"\n    [attr.aria-label]=\"'Image comparison slider control'\">\n    <div class=\"handle-line\"></div>\n    <div class=\"handle-grip\">\n      <ngs-icon name=\"fluent:chevron-left-24-regular\"/>\n      <ngs-icon name=\"fluent:chevron-right-24-regular\"/>\n    </div>\n  </div>\n</div>\n", styles: [":host{display:block;position:relative;overflow:hidden;width:100%;-webkit-user-select:none;user-select:none}:host .comparison-slider-container{position:relative;width:100%;height:100%;overflow:hidden;cursor:default}:host .image-wrapper{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden}:host .image-wrapper>::slotted(*){display:block;width:100%;height:100%;object-fit:cover}:host .before-image-slot{z-index:1}:host .after-image-slot{z-index:2}:host .slider-handle{position:absolute;top:0;bottom:0;width:40px;transform:translate(-50%);cursor:ew-resize;display:flex;align-items:center;justify-content:center;z-index:10}:host .slider-handle .handle-line{position:absolute;top:0;bottom:0;left:50%;transform:translate(-50%);width:4px;background:#fff;pointer-events:none}:host .slider-handle .handle-line:before{content:\"\";position:absolute;top:0;bottom:0;left:0;width:1px;background:#000}:host .slider-handle .handle-line:after{content:\"\";position:absolute;top:0;bottom:0;right:0;width:1px;background:#000}:host .slider-handle .handle-grip{height:36px;display:flex;align-items:center;justify-content:center;z-index:1;pointer-events:none;gap:calc(var(--spacing, .25rem) * 3)}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
        }], ctorParameters: () => [], propDecorators: { sliderContainerRef: [{ type: i0.ViewChild, args: ['sliderContainer', { isSignal: true }] }], handleRef: [{ type: i0.ViewChild, args: ['handle', { isSignal: true }] }], initialPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialPosition", required: false }] }] } });

class ComparisonSliderAfterImageDirective {
    onDragStart(event) {
        event.preventDefault();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComparisonSliderAfterImageDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.4", type: ComparisonSliderAfterImageDirective, isStandalone: true, selector: "[ngsComparisonSliderAfterImage]", host: { listeners: { "dragstart": "onDragStart($event)" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComparisonSliderAfterImageDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ngsComparisonSliderAfterImage]',
                    host: {
                        '(dragstart)': 'onDragStart($event)'
                    }
                }]
        }] });

class ComparisonSliderBeforeImageDirective {
    onDragStart(event) {
        event.preventDefault();
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComparisonSliderBeforeImageDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
    static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.4", type: ComparisonSliderBeforeImageDirective, isStandalone: true, selector: "[ngsComparisonSliderBeforeImage]", host: { listeners: { "dragstart": "onDragStart($event)" } }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: ComparisonSliderBeforeImageDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ngsComparisonSliderBeforeImage]',
                    host: {
                        '(dragstart)': 'onDragStart($event)'
                    }
                }]
        }] });

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

export { ComparisonSlider, ComparisonSliderAfterImageDirective, ComparisonSliderBeforeImageDirective };
//# sourceMappingURL=ngstarter-ui-components-comparison-slider.mjs.map
