import * as i0 from '@angular/core';
import { Pipe, input, computed, output, signal, inject, ChangeDetectorRef, ElementRef, Component, ChangeDetectionStrategy, Input, HostListener, Injectable, InjectionToken } from '@angular/core';
import { fromEvent, Subject, of, firstValueFrom, race } from 'rxjs';
import { map, take, switchMap } from 'rxjs/operators';
import { CdkOverlayOrigin, CdkConnectedOverlay } from '@angular/cdk/overlay';
import { DOCUMENT, AsyncPipe } from '@angular/common';
import { NgControl } from '@angular/forms';
import * as i1 from '@angular/material/button';
import { MatButtonModule } from '@angular/material/button';
import { MatFormFieldControl } from '@angular/material/form-field';
import * as i2 from '@angular/material/icon';
import { MatIconModule } from '@angular/material/icon';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
import * as i3 from '@angular/material/tooltip';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MethodDirective } from '@rxap/directives';

class ReadAsDataURLPipe {
    async transform(file) {
        if (!file) {
            return null;
        }
        const reader = new FileReader();
        const dataUrl$ = fromEvent(reader, 'load').pipe(map(event => event.target.result), take(1));
        reader.readAsDataURL(file);
        return dataUrl$.toPromise();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ReadAsDataURLPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.1.3", ngImport: i0, type: ReadAsDataURLPipe, isStandalone: true, name: "readAsDataURL" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: ReadAsDataURLPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'readAsDataURL',
                    standalone: true,
                }]
        }] });

class UploadButtonComponent {
    static { this.nextId = 0; }
    get placeholder() {
        return this._placeholder;
    }
    set placeholder(plh) {
        this._placeholder = plh;
        this.stateChanges.next();
    }
    get empty() {
        return this.value === null;
    }
    get id() {
        return `rxap-upload-button-${UploadButtonComponent.nextId++}`;
    }
    constructor() {
        this.accept = input('**/**');
        this.acceptAttribute = computed(() => Array.isArray(this.accept) ? this.accept.join(',') : this.accept);
        this.allowDownload = input(false);
        this.uploaded = output();
        this.isImageUploaded = signal(false);
        this.positions = [
            {
                originY: 'bottom',
                originX: 'start',
                overlayX: 'start',
                overlayY: 'top',
                offsetY: 12,
            },
        ];
        this.touched = false;
        // region MatFormFieldControl
        this.disabled = false;
        this.controlType = 'rxap-upload-button';
        this.errorState = false;
        this.focused = false;
        this.required = false;
        this.shouldLabelFloat = true;
        this.stateChanges = new Subject();
        this.value = null;
        this.ngControl = inject(NgControl, {
            optional: true,
            self: true,
        });
        this.snackBar = inject(MatSnackBar);
        this.cdr = inject(ChangeDetectorRef);
        this._elementRef = inject(ElementRef);
        this.document = inject(DOCUMENT);
        if (this.ngControl != null) {
            this.ngControl.valueAccessor = this;
        }
    }
    get isImage() {
        return !!this.value?.type.match(/^image\//);
    }
    // region MatFormFieldControl
    // eslint-disable-next-line @typescript-eslint/no-empty-function
    onContainerClick(event) {
    }
    setDescribedByIds(ids) {
        this._elementRef
            .nativeElement
            .querySelector('button')
            ?.setAttribute('aria-describedby', ids.join(' '));
    }
    ngOnDestroy() {
        this.stateChanges.complete();
    }
    registerOnChange(fn) {
        this.onChange = fn;
    }
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    setDisabledState(isDisabled) {
        this.disabled = isDisabled;
    }
    // endregion
    writeValue(file) {
        this.value = file;
        this.cdr.detectChanges();
    }
    openOverlay() {
        if (this.value?.type.match(/^image\//)) {
            this.isImageUploaded.set(true);
        }
    }
    onFocusIn(event) {
        if (!this.focused) {
            this.focused = true;
            this.stateChanges.next();
        }
    }
    onFocusOut(event) {
        if (!this._elementRef.nativeElement.contains(event.relatedTarget)) {
            this.touched = true;
            this.focused = false;
            if (this.onTouched) {
                this.onTouched();
            }
            this.stateChanges.next();
        }
    }
    download() {
        if (this.value) {
            const elm = this.document.createElement('a');
            this.document.body.appendChild(elm);
            elm.href = URL.createObjectURL(this.value);
            elm.setAttribute('download', this.value.name);
            elm.click();
            this.document.body.removeChild(elm);
        }
    }
    onFileInputChange($event) {
        const files = $event?.target?.files ?? {};
        const file = Object.values(files)[0];
        if (!file) {
            this.snackBar.open('No file selected', 'close', { duration: 3000 });
        }
        else {
            this.uploaded.emit(file);
            this.value = file;
            if (this.onChange) {
                this.onChange(file);
            }
            this.stateChanges.next();
        }
    }
    clear() {
        this.value = null;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: UploadButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.1.3", type: UploadButtonComponent, isStandalone: true, selector: "rxap-upload-button", inputs: { accept: { classPropertyName: "accept", publicName: "accept", isSignal: true, isRequired: false, transformFunction: null }, allowDownload: { classPropertyName: "allowDownload", publicName: "allowDownload", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: false, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { uploaded: "uploaded" }, host: { listeners: { "focusin": "onFocusIn($event)", "focusout": "onFocusOut($event)" }, classAttribute: "rxap-upload-button" }, providers: [
            {
                provide: MatFormFieldControl,
                useExisting: UploadButtonComponent,
            },
        ], ngImport: i0, template: "<div class=\"flex flex-row gap-2 items-center\">\n  <button\n    #trigger=\"cdkOverlayOrigin\"\n    [disabled]=\"disabled\"\n    (click)=\"fileInput.click()\"\n    cdkOverlayOrigin\n    class=\"grow-0\"\n    mat-stroked-button\n    type=\"button\">\n    <span class=\"flex flex-row justify-center items-center gap-3\">\n      <mat-icon class=\"grow-0\" svgIcon=\"upload\"></mat-icon>&nbsp;\n      @if (value) {\n        <span class=\"truncate grow-0\">{{ value.name }}</span>\n      } @else {\n        @if (placeholder) {\n          <span>{{ placeholder }}</span>\n        }\n        <ng-content></ng-content>\n      }\n    </span>\n  </button>\n  @if (isImage) {\n    <button (click)=\"openOverlay()\"\n            class=\"grow-0\"\n            i18n-matTooltip\n            mat-icon-button\n            matTooltip=\"Open image preview\"\n            type=\"button\">\n      <mat-icon>preview</mat-icon>\n    </button>\n  }\n  @if (allowDownload() && value) {\n    <button (click)=\"download()\" class=\"grow-0\" i18n-matTooltip mat-icon-button\n            matTooltip=\"Download file\" type=\"button\">\n      <mat-icon svgIcon=\"download\"></mat-icon>\n    </button>\n  }\n</div>\n\n<ng-template\n  (backdropClick)=\"isImageUploaded.set(false)\"\n  [cdkConnectedOverlayHasBackdrop]=\"true\"\n  [cdkConnectedOverlayOpen]=\"isImageUploaded()\"\n  [cdkConnectedOverlayOrigin]=\"trigger\"\n  [cdkConnectedOverlayPositions]=\"positions\"\n  cdkConnectedOverlay\n>\n  <div class=\"bg-white dark:bg-black drop-shadow-xl overlay-container p-2 rounded overflow-auto\">\n    <img [src]=\"value | readAsDataURL | async\" class=\"w-full\">\n  </div>\n</ng-template>\n\n<input #fileInput (change)=\"onFileInputChange($event)\" [accept]=\"acceptAttribute()\" [id]=\"id\" class=\"hidden\"\n       type=\"file\">\n", styles: [".overlay-container{min-width:256px;max-width:50vw;max-height:50vh}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1.MatButton, selector: "    button[mat-button], button[mat-raised-button], button[mat-flat-button],    button[mat-stroked-button]  ", exportAs: ["matButton"] }, { kind: "component", type: i1.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i3.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: ReadAsDataURLPipe, name: "readAsDataURL" }, { kind: "ngmodule", type: MatSnackBarModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: UploadButtonComponent, decorators: [{
            type: Component,
            args: [{ selector: 'rxap-upload-button', changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'rxap-upload-button' }, providers: [
                        {
                            provide: MatFormFieldControl,
                            useExisting: UploadButtonComponent,
                        },
                    ], imports: [
                        MatButtonModule,
                        CdkOverlayOrigin,
                        MethodDirective,
                        MatIconModule,
                        MatProgressSpinnerModule,
                        MatTooltipModule,
                        CdkConnectedOverlay,
                        AsyncPipe,
                        ReadAsDataURLPipe,
                        MatSnackBarModule,
                    ], template: "<div class=\"flex flex-row gap-2 items-center\">\n  <button\n    #trigger=\"cdkOverlayOrigin\"\n    [disabled]=\"disabled\"\n    (click)=\"fileInput.click()\"\n    cdkOverlayOrigin\n    class=\"grow-0\"\n    mat-stroked-button\n    type=\"button\">\n    <span class=\"flex flex-row justify-center items-center gap-3\">\n      <mat-icon class=\"grow-0\" svgIcon=\"upload\"></mat-icon>&nbsp;\n      @if (value) {\n        <span class=\"truncate grow-0\">{{ value.name }}</span>\n      } @else {\n        @if (placeholder) {\n          <span>{{ placeholder }}</span>\n        }\n        <ng-content></ng-content>\n      }\n    </span>\n  </button>\n  @if (isImage) {\n    <button (click)=\"openOverlay()\"\n            class=\"grow-0\"\n            i18n-matTooltip\n            mat-icon-button\n            matTooltip=\"Open image preview\"\n            type=\"button\">\n      <mat-icon>preview</mat-icon>\n    </button>\n  }\n  @if (allowDownload() && value) {\n    <button (click)=\"download()\" class=\"grow-0\" i18n-matTooltip mat-icon-button\n            matTooltip=\"Download file\" type=\"button\">\n      <mat-icon svgIcon=\"download\"></mat-icon>\n    </button>\n  }\n</div>\n\n<ng-template\n  (backdropClick)=\"isImageUploaded.set(false)\"\n  [cdkConnectedOverlayHasBackdrop]=\"true\"\n  [cdkConnectedOverlayOpen]=\"isImageUploaded()\"\n  [cdkConnectedOverlayOrigin]=\"trigger\"\n  [cdkConnectedOverlayPositions]=\"positions\"\n  cdkConnectedOverlay\n>\n  <div class=\"bg-white dark:bg-black drop-shadow-xl overlay-container p-2 rounded overflow-auto\">\n    <img [src]=\"value | readAsDataURL | async\" class=\"w-full\">\n  </div>\n</ng-template>\n\n<input #fileInput (change)=\"onFileInputChange($event)\" [accept]=\"acceptAttribute()\" [id]=\"id\" class=\"hidden\"\n       type=\"file\">\n", styles: [".overlay-container{min-width:256px;max-width:50vw;max-height:50vh}\n"] }]
        }], ctorParameters: () => [], propDecorators: { disabled: [{
                type: Input
            }], required: [{
                type: Input
            }], placeholder: [{
                type: Input
            }], onFocusIn: [{
                type: HostListener,
                args: ['focusin', ['$event']]
            }], onFocusOut: [{
                type: HostListener,
                args: ['focusout', ['$event']]
            }] } });

class FileUploadMethod {
    constructor() {
        this.progress$ = new Subject();
        this._fileInput = null;
        this._document = null;
    }
    get document() {
        if (!this._document) {
            this._document = this.getDocument();
        }
        return this._document;
    }
    call(parameters) {
        const accept = parameters?.accept ?? '**/**';
        const fileInput = parameters?.fileInput ?? this.addInputToDom(accept);
        fileInput.setAttribute('accept', accept);
        const change$ = fromEvent(fileInput, 'change').pipe(map(event => this.handleFileInputChange(event)), switchMap(file => file ? this.readFile(file) : of(null)), take(1));
        const cancel$ = fromEvent(this.document.body, 'focus').pipe(take(1), map(() => null));
        fileInput.click();
        return firstValueFrom(race(change$, cancel$));
    }
    setDocument(document) {
        this._document = document;
    }
    handleFileInputChange(event) {
        this.removeInputFromDom();
        const files = event?.target?.files ?? {};
        if (Object.keys(files).length !== 1) {
            throw new Error('File upload failed');
        }
        let file = null;
        for (const key in files) {
            if (!isNaN(parseInt(key, 10))) {
                file = files[key];
            }
        }
        return file;
    }
    removeInputFromDom() {
        if (this._fileInput) {
            this.document.body.removeChild(this._fileInput);
        }
        this._fileInput = null;
    }
    readFile(file) {
        const reader = new FileReader();
        const loadFile$ = fromEvent(reader, 'load').pipe(map(event => new File([event.target.result], file.name, {
            type: file.type,
            lastModified: file.lastModified,
        })), take(1));
        fromEvent(reader, 'progress').pipe(map((progress) => {
            if (progress instanceof ProgressEvent) {
                return progress.loaded / progress.total * 100;
            }
            throw new Error('The progress event is not an instance of ProgressEvent');
        })).subscribe(this.progress$);
        reader.readAsArrayBuffer(file);
        return firstValueFrom(loadFile$);
    }
    addInputToDom(accept) {
        const fileInput = this.document.createElement('input');
        fileInput.setAttribute('type', 'file');
        fileInput.setAttribute('style', 'display: none');
        fileInput.setAttribute('accept', accept);
        this.document.body.appendChild(fileInput);
        return this._fileInput = fileInput;
    }
    getDocument() {
        return window.document;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: FileUploadMethod, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: FileUploadMethod }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.3", ngImport: i0, type: FileUploadMethod, decorators: [{
            type: Injectable
        }] });

const FILE_UPLOAD_METHOD = new InjectionToken('file-upload-method', {
    providedIn: 'root',
    factory: () => new FileUploadMethod(),
});

// region upload-button
// endregion

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

export { FILE_UPLOAD_METHOD, FileUploadMethod, ReadAsDataURLPipe, UploadButtonComponent };
//# sourceMappingURL=rxap-upload.mjs.map
