import * as i0 from '@angular/core';
import { input, output, computed, signal, inject, ElementRef, effect, ChangeDetectionStrategy, Component } from '@angular/core';

class Crop {
    minWidth = input(100, ...(ngDevMode ? [{ debugName: "minWidth" }] : /* istanbul ignore next */ []));
    minHeight = input(100, ...(ngDevMode ? [{ debugName: "minHeight" }] : /* istanbul ignore next */ []));
    shape = input('rectangle', ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
    selectionApplied = output();
    isCircle = computed(() => this.shape() === 'circle', ...(ngDevMode ? [{ debugName: "isCircle" }] : /* istanbul ignore next */ []));
    selection = signal({ top: 20, right: 20, bottom: 20, left: 20 }, ...(ngDevMode ? [{ debugName: "selection" }] : /* istanbul ignore next */ []));
    elementRef = inject(ElementRef);
    activeDragHandle = signal(null, ...(ngDevMode ? [{ debugName: "activeDragHandle" }] : /* istanbul ignore next */ []));
    startDragPosition = signal(null, ...(ngDevMode ? [{ debugName: "startDragPosition" }] : /* istanbul ignore next */ []));
    startDragSelection = signal(null, ...(ngDevMode ? [{ debugName: "startDragSelection" }] : /* istanbul ignore next */ []));
    constructor() {
        effect(() => {
            if (this.isCircle() && this.elementRef.nativeElement.isConnected) {
                this.resetSelectionToSquare();
            }
        });
    }
    ngAfterViewInit() {
        if (this.isCircle()) {
            const hostEl = this.elementRef.nativeElement;
            if (hostEl.offsetWidth > 0) {
                this.resetSelectionToSquare();
            }
            else {
                const observer = new ResizeObserver(() => {
                    if (hostEl.offsetWidth > 0) {
                        this.resetSelectionToSquare();
                        observer.disconnect();
                    }
                });
                observer.observe(hostEl);
            }
        }
    }
    resetSelectionToSquare() {
        const hostEl = this.elementRef.nativeElement;
        const hostWidth = hostEl.offsetWidth;
        const hostHeight = hostEl.offsetHeight;
        if (hostWidth === 0 || hostHeight === 0)
            return;
        const size = Math.min(hostWidth, hostHeight) * 0.8;
        const left = (hostWidth - size) / 2;
        const top = (hostHeight - size) / 2;
        this.selection.set({
            top: top,
            right: (hostWidth - size) / 2,
            bottom: (hostHeight - size) / 2,
            left: left,
        });
        // Emit the new selection state after it has been programmatically changed.
        // Use a timeout to avoid potential "changed after checked" errors.
        setTimeout(() => this.emitSelection(), 0);
    }
    selectionStyle = computed(() => ({
        top: `${this.selection().top}px`,
        right: `${this.selection().right}px`,
        bottom: `${this.selection().bottom}px`,
        left: `${this.selection().left}px`,
    }), ...(ngDevMode ? [{ debugName: "selectionStyle" }] : /* istanbul ignore next */ []));
    onDragStart(event, handle) {
        event.preventDefault();
        event.stopPropagation();
        this.activeDragHandle.set(handle);
        this.startDragPosition.set({ x: event.clientX, y: event.clientY });
        this.startDragSelection.set(this.selection());
    }
    onDragEnd() {
        if (!this.activeDragHandle()) {
            return;
        }
        this.activeDragHandle.set(null);
        this.emitSelection();
    }
    emitSelection() {
        const hostEl = this.elementRef.nativeElement;
        const containerWidth = hostEl.offsetWidth;
        const containerHeight = hostEl.offsetHeight;
        if (containerWidth === 0 || containerHeight === 0) {
            return;
        }
        const { top, right, bottom, left } = this.selection();
        const width = containerWidth - left - right;
        const height = containerHeight - top - bottom;
        this.selectionApplied.emit({
            shape: this.shape(),
            pixels: {
                top,
                right,
                bottom,
                left,
                width,
                height,
            },
            percentages: {
                top: (top / containerHeight) * 100,
                right: (right / containerWidth) * 100,
                bottom: (bottom / containerHeight) * 100,
                left: (left / containerWidth) * 100,
            },
            containerWidth,
            containerHeight,
        });
    }
    onDrag(event) {
        const handle = this.activeDragHandle();
        if (!handle)
            return;
        const startPos = this.startDragPosition();
        const startSelection = this.startDragSelection();
        const dx = event.clientX - startPos.x;
        const dy = event.clientY - startPos.y;
        const hostRect = this.elementRef.nativeElement.getBoundingClientRect();
        this.selection.update(() => {
            const newSelection = { ...startSelection };
            if (handle === 'move') {
                const selectionWidth = hostRect.width - startSelection.left - startSelection.right;
                const selectionHeight = hostRect.height - startSelection.top - startSelection.bottom;
                newSelection.top = Math.max(0, Math.min(startSelection.top + dy, hostRect.height - selectionHeight));
                newSelection.left = Math.max(0, Math.min(startSelection.left + dx, hostRect.width - selectionWidth));
                newSelection.bottom = hostRect.height - newSelection.top - selectionHeight;
                newSelection.right = hostRect.width - newSelection.left - selectionWidth;
                return newSelection;
            }
            let currentDx = dx;
            let currentDy = dy;
            if (this.isCircle() && handle.includes('-')) {
                if (handle === 'top-left' || handle === 'bottom-right') {
                    currentDy = currentDx;
                }
                else {
                    currentDy = -currentDx;
                }
            }
            if (handle.includes('top'))
                newSelection.top = startSelection.top + currentDy;
            if (handle.includes('bottom'))
                newSelection.bottom = startSelection.bottom - currentDy;
            if (handle.includes('left'))
                newSelection.left = startSelection.left + currentDx;
            if (handle.includes('right'))
                newSelection.right = startSelection.right - currentDx;
            const minW = this.minWidth();
            const minH = this.isCircle() ? minW : this.minHeight();
            if (hostRect.width - newSelection.left - newSelection.right < minW) {
                if (handle.includes('left'))
                    newSelection.left = hostRect.width - newSelection.right - minW;
                else
                    newSelection.right = hostRect.width - newSelection.left - minW;
            }
            if (hostRect.height - newSelection.top - newSelection.bottom < minH) {
                if (handle.includes('top'))
                    newSelection.top = hostRect.height - newSelection.bottom - minH;
                else
                    newSelection.bottom = hostRect.height - newSelection.top - minH;
            }
            newSelection.top = Math.max(0, newSelection.top);
            newSelection.bottom = Math.max(0, newSelection.bottom);
            newSelection.left = Math.max(0, newSelection.left);
            newSelection.right = Math.max(0, newSelection.right);
            return newSelection;
        });
    }
    static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: Crop, deps: [], target: i0.ɵɵFactoryTarget.Component });
    static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.4", type: Crop, isStandalone: true, selector: "ngs-crop", inputs: { minWidth: { classPropertyName: "minWidth", publicName: "minWidth", isSignal: true, isRequired: false, transformFunction: null }, minHeight: { classPropertyName: "minHeight", publicName: "minHeight", isSignal: true, isRequired: false, transformFunction: null }, shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionApplied: "selectionApplied" }, host: { listeners: { "document:mouseup": "onDragEnd()", "document:mousemove": "onDrag($event)" } }, ngImport: i0, template: "<div class=\"crop-viewport\">\n  <ng-content />\n  <div\n    class=\"crop-selection-area\"\n    [class.is-circle]=\"isCircle()\"\n    [style]=\"selectionStyle()\">\n  </div>\n</div>\n\n<!-- Handles are now outside the viewport to prevent clipping -->\n<div\n  class=\"crop-handles-overlay\"\n  [style]=\"selectionStyle()\">\n  <div class=\"crop-handle move-handle\" (mousedown)=\"onDragStart($event, 'move')\"></div>\n  <div class=\"crop-handle top-left\" (mousedown)=\"onDragStart($event, 'top-left')\"></div>\n  <div class=\"crop-handle top-right\" (mousedown)=\"onDragStart($event, 'top-right')\"></div>\n  <div class=\"crop-handle bottom-left\" (mousedown)=\"onDragStart($event, 'bottom-left')\"></div>\n  <div class=\"crop-handle bottom-right\" (mousedown)=\"onDragStart($event, 'bottom-right')\"></div>\n\n  <div class=\"crop-handle top\" [class.hidden]=\"isCircle()\" (mousedown)=\"onDragStart($event, 'top')\"></div>\n  <div class=\"crop-handle right\" [class.hidden]=\"isCircle()\" (mousedown)=\"onDragStart($event, 'right')\"></div>\n  <div class=\"crop-handle bottom\" [class.hidden]=\"isCircle()\" (mousedown)=\"onDragStart($event, 'bottom')\"></div>\n  <div class=\"crop-handle left\" [class.hidden]=\"isCircle()\" (mousedown)=\"onDragStart($event, 'left')\"></div>\n</div>\n", styles: [":host{display:inline-block;position:relative;-webkit-user-select:none;user-select:none}:host .crop-viewport{position:relative;width:100%;height:100%;overflow:hidden}:host ::ng-deep>.crop-viewport>*:first-child{display:block;max-width:100%;height:auto}:host .crop-selection-area{position:absolute;box-shadow:0 0 0 2000px #00000080}:host .crop-selection-area.is-circle{border-radius:50%}:host .crop-handles-overlay{position:absolute}:host .crop-handles-overlay.is-circle{border-radius:50%}:host .crop-handle{position:absolute;width:14px;height:14px;background:#ffffffe6;border:1px solid rgba(0,0,0,.5);border-radius:50%}:host .crop-handle.hidden{display:none}:host .move-handle{position:absolute;inset:0;width:auto;height:auto;background:transparent;border:none;border-radius:0;cursor:move}.is-circle :host .move-handle{border-radius:50%}:host .top-left{top:-7px;left:-7px;cursor:nwse-resize}:host .top-right{top:-7px;right:-7px;cursor:nesw-resize}:host .bottom-left{bottom:-7px;left:-7px;cursor:nesw-resize}:host .bottom-right{bottom:-7px;right:-7px;cursor:nwse-resize}:host .top{top:-7px;left:50%;transform:translate(-50%);cursor:ns-resize}:host .right{top:50%;right:-7px;transform:translateY(-50%);cursor:ew-resize}:host .bottom{bottom:-7px;left:50%;transform:translate(-50%);cursor:ns-resize}:host .left{top:50%;left:-7px;transform:translateY(-50%);cursor:ew-resize}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.4", ngImport: i0, type: Crop, decorators: [{
            type: Component,
            args: [{ selector: 'ngs-crop', changeDetection: ChangeDetectionStrategy.OnPush, host: {
                        '(document:mouseup)': 'onDragEnd()',
                        '(document:mousemove)': 'onDrag($event)',
                    }, template: "<div class=\"crop-viewport\">\n  <ng-content />\n  <div\n    class=\"crop-selection-area\"\n    [class.is-circle]=\"isCircle()\"\n    [style]=\"selectionStyle()\">\n  </div>\n</div>\n\n<!-- Handles are now outside the viewport to prevent clipping -->\n<div\n  class=\"crop-handles-overlay\"\n  [style]=\"selectionStyle()\">\n  <div class=\"crop-handle move-handle\" (mousedown)=\"onDragStart($event, 'move')\"></div>\n  <div class=\"crop-handle top-left\" (mousedown)=\"onDragStart($event, 'top-left')\"></div>\n  <div class=\"crop-handle top-right\" (mousedown)=\"onDragStart($event, 'top-right')\"></div>\n  <div class=\"crop-handle bottom-left\" (mousedown)=\"onDragStart($event, 'bottom-left')\"></div>\n  <div class=\"crop-handle bottom-right\" (mousedown)=\"onDragStart($event, 'bottom-right')\"></div>\n\n  <div class=\"crop-handle top\" [class.hidden]=\"isCircle()\" (mousedown)=\"onDragStart($event, 'top')\"></div>\n  <div class=\"crop-handle right\" [class.hidden]=\"isCircle()\" (mousedown)=\"onDragStart($event, 'right')\"></div>\n  <div class=\"crop-handle bottom\" [class.hidden]=\"isCircle()\" (mousedown)=\"onDragStart($event, 'bottom')\"></div>\n  <div class=\"crop-handle left\" [class.hidden]=\"isCircle()\" (mousedown)=\"onDragStart($event, 'left')\"></div>\n</div>\n", styles: [":host{display:inline-block;position:relative;-webkit-user-select:none;user-select:none}:host .crop-viewport{position:relative;width:100%;height:100%;overflow:hidden}:host ::ng-deep>.crop-viewport>*:first-child{display:block;max-width:100%;height:auto}:host .crop-selection-area{position:absolute;box-shadow:0 0 0 2000px #00000080}:host .crop-selection-area.is-circle{border-radius:50%}:host .crop-handles-overlay{position:absolute}:host .crop-handles-overlay.is-circle{border-radius:50%}:host .crop-handle{position:absolute;width:14px;height:14px;background:#ffffffe6;border:1px solid rgba(0,0,0,.5);border-radius:50%}:host .crop-handle.hidden{display:none}:host .move-handle{position:absolute;inset:0;width:auto;height:auto;background:transparent;border:none;border-radius:0;cursor:move}.is-circle :host .move-handle{border-radius:50%}:host .top-left{top:-7px;left:-7px;cursor:nwse-resize}:host .top-right{top:-7px;right:-7px;cursor:nesw-resize}:host .bottom-left{bottom:-7px;left:-7px;cursor:nesw-resize}:host .bottom-right{bottom:-7px;right:-7px;cursor:nwse-resize}:host .top{top:-7px;left:50%;transform:translate(-50%);cursor:ns-resize}:host .right{top:50%;right:-7px;transform:translateY(-50%);cursor:ew-resize}:host .bottom{bottom:-7px;left:50%;transform:translate(-50%);cursor:ns-resize}:host .left{top:50%;left:-7px;transform:translateY(-50%);cursor:ew-resize}\n/*! tailwindcss v4.2.2 | MIT License | https://tailwindcss.com */\n"] }]
        }], ctorParameters: () => [], propDecorators: { minWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "minWidth", required: false }] }], minHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "minHeight", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], selectionApplied: [{ type: i0.Output, args: ["selectionApplied"] }] } });

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

export { Crop };
//# sourceMappingURL=ngstarter-ui-components-crop.mjs.map
