import { take, switchMap } from 'rxjs/operators';
import { Subject, fromEvent, race } from 'rxjs';
import { __decorate } from 'tslib';
import { EventEmitter, ElementRef, Input, Output, HostListener, Component, ChangeDetectionStrategy, ViewEncapsulation, HostBinding, ViewContainerRef, Directive, ChangeDetectorRef, ComponentFactoryResolver, ViewChild, Injector, ApplicationRef, Injectable, NgModule } from '@angular/core';
import { trigger, transition, group, query, style, animate } from '@angular/animations';
import { Patch } from '@bravobit/bb-foundation';
import { BbButton, ElementsModule } from '@bravobit/bb-foundation/elements';
import { LocalizeModule } from '@bravobit/bb-foundation/localize';
import { CommonModule } from '@angular/common';

class BbDialogRef {
    constructor() {
        // Data.
        this._afterClosed$ = new Subject();
        this._overlayClicked$ = new Subject();
    }
    get afterClosed() {
        return this._afterClosed$.pipe(take(1));
    }
    get overlayClicked() {
        return this._overlayClicked$.pipe(take(1));
    }
    onOverlayClicked() {
        this._overlayClicked$.next();
    }
    close(result) {
        this._afterClosed$.next(result);
    }
}

class BbDialogConfig {
}

let BbDialogOverlay = class BbDialogOverlay {
    constructor(_elementRef) {
        this._elementRef = _elementRef;
        // Inputs.
        this.animations = true;
        // Outputs.
        this.closeRequested = new EventEmitter();
        // State.
        this._state = 'open';
        this._closed$ = new Subject();
    }
    get state() {
        return this.animations
            ? this._state
            : 'none';
    }
    ngAfterViewInit() {
        this.listenForClicks();
    }
    ngOnDestroy() {
        this._subscription && this._subscription.unsubscribe();
    }
    onKeyEvent(event) {
        if (event.key === 'Escape') {
            this.closeRequested.emit();
        }
    }
    onAnimationDone(event) {
        // Check if the dialog is being destroyed.
        if (!['close', 'none'].includes(event.toState)) {
            return;
        }
        this._closed$.next();
        this._closed$.complete();
    }
    close() {
        this._state = 'close';
        return this._closed$.pipe(take(1)).toPromise();
    }
    listenForClicks() {
        if (!this._elementRef || !this._elementRef.nativeElement) {
            return;
        }
        const mouseDown$ = fromEvent(this._elementRef.nativeElement, 'mousedown');
        const touchStart$ = fromEvent(this._elementRef.nativeElement, 'touchstart');
        const start$ = race([mouseDown$, touchStart$]);
        const mouseUp$ = fromEvent(this._elementRef.nativeElement, 'mouseup');
        const touchEnd$ = fromEvent(this._elementRef.nativeElement, 'touchend');
        const end$ = race([mouseUp$, touchEnd$]);
        this._subscription = start$.pipe(switchMap(() => end$)).subscribe(() => {
            this.closeRequested.next();
        });
    }
};
BbDialogOverlay.ctorParameters = () => [
    { type: ElementRef }
];
__decorate([
    Input()
], BbDialogOverlay.prototype, "animations", void 0);
__decorate([
    Output()
], BbDialogOverlay.prototype, "closeRequested", void 0);
__decorate([
    HostListener('window:keyup', ['$event'])
], BbDialogOverlay.prototype, "onKeyEvent", null);
__decorate([
    HostListener('@bbDialogAnimation.done', ['$event'])
], BbDialogOverlay.prototype, "onAnimationDone", null);
BbDialogOverlay = __decorate([
    Component({
        selector: 'bb-dialog-overlay',
        template: "<div class=\"bb-dialog-overlay-backdrop\"></div>\r\n\r\n<ng-content select=\"[bb-dialog-modal]\"></ng-content>\r\n",
        changeDetection: ChangeDetectionStrategy.OnPush,
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        host: { 'class': 'bb-dialog-overlay', '[@bbDialogAnimation]': 'state' },
        animations: [
            trigger('bbDialogAnimation', [
                transition('* => none', []),
                transition(':enter, * => open', [
                    group([
                        query('.bb-dialog-overlay-backdrop', [
                            style({ opacity: 0 }),
                            animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({ opacity: 1 }))
                        ]),
                        query('.bb-dialog-modal', [
                            style({ transform: 'scale(0.95)' }),
                            animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({ transform: 'scale(1)' }))
                        ])
                    ])
                ]),
                transition(':leave, * => close', [
                    group([
                        query('.bb-dialog-overlay-backdrop', [
                            animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({ opacity: 0 }))
                        ]),
                        query('.bb-dialog-modal', [
                            animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({ opacity: 0, transform: 'scale(0.95)' }))
                        ])
                    ])
                ])
            ])
        ],
        styles: [".bb-dialog-overlay,.bb-dialog-overlay-backdrop{top:0;left:0;right:0;bottom:0;display:-ms-flexbox;display:flex;z-index:1000;position:fixed;-ms-flex-direction:column;flex-direction:column}.bb-dialog-overlay{padding:20px}.bb-dialog-overlay-backdrop{background-color:rgba(0,0,0,.5)}.bb-dialog-overlay-component{z-index:1001;display:block;position:relative}"]
    })
], BbDialogOverlay);

let BbDialogModal = class BbDialogModal {
    constructor(_patch) {
        this._patch = _patch;
        // Styling.
        this.maxWidth = '420px';
    }
    onOverlayClickedEvent(event) {
        event.stopPropagation();
    }
    ngOnInit() {
        this._patch.mobileVerticalHeight();
    }
};
BbDialogModal.ctorParameters = () => [
    { type: Patch }
];
__decorate([
    HostBinding('style.max-width'), Input()
], BbDialogModal.prototype, "maxWidth", void 0);
__decorate([
    HostListener('click', ['$event']),
    HostListener('touchstart', ['$event']),
    HostListener('touchend', ['$event']),
    HostListener('mouseup', ['$event']),
    HostListener('mousedown', ['$event'])
], BbDialogModal.prototype, "onOverlayClickedEvent", null);
BbDialogModal = __decorate([
    Component({
        selector: '[bb-dialog-modal]',
        template: "<ng-content select=\"[bb-dialog-header]\">\r\n\r\n</ng-content>\r\n\r\n<div class=\"bb-dialog-modal-body\">\r\n    <ng-content></ng-content>\r\n</div>\r\n\r\n<ng-content select=\"[bb-dialog-actions]\">\r\n\r\n</ng-content>\r\n",
        changeDetection: ChangeDetectionStrategy.OnPush,
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        host: {
            'class': 'bb-dialog-modal',
            'role': 'dialog'
        },
        styles: [".bb-dialog-modal{width:100%;margin:auto;z-index:1001;display:-ms-flexbox;display:flex;max-width:420px;border-radius:4px;position:relative;-ms-flex-direction:column;flex-direction:column;background-color:#fff;max-height:calc((var(--vh,1vh) * 100) - 40px)}.bb-dialog-modal-body{padding:20px;color:#738694;font-size:13px;overflow-y:auto;line-height:1.4;background-color:#f1f3f6}"]
    })
], BbDialogModal);

let BbDialogHeader = class BbDialogHeader {
    constructor() {
        // Inputs.
        this.iconName = null;
        this.iconColor = 'black';
        // Outputs.
        this.closeRequested = new EventEmitter();
    }
};
__decorate([
    Input()
], BbDialogHeader.prototype, "iconName", void 0);
__decorate([
    Input()
], BbDialogHeader.prototype, "iconColor", void 0);
__decorate([
    Output()
], BbDialogHeader.prototype, "closeRequested", void 0);
BbDialogHeader = __decorate([
    Component({
        selector: '[bb-dialog-header]',
        template: "<div class=\"bb-dialog-header-row\">\r\n    <div *ngIf=\"iconName as icon\"\r\n         [style.color]=\"iconColor\"\r\n         class=\"bb-dialog-header-icon\">\r\n        <i class=\"material-icons\">{{ icon }}</i>\r\n    </div>\r\n\r\n    <div class=\"bb-dialog-header-content\">\r\n        <ng-content></ng-content>\r\n    </div>\r\n\r\n    <button *ngIf=\"closeRequested?.observers?.length > 0\"\r\n            (click)=\"closeRequested?.emit()\"\r\n            type=\"button\"\r\n            class=\"bb-dialog-header-close\">\r\n    </button>\r\n</div>\r\n\r\n<nav class=\"bb-dialog-header-navigation\">\r\n    <ng-content select=\"[bb-dialog-link]\"></ng-content>\r\n</nav>\r\n",
        changeDetection: ChangeDetectionStrategy.OnPush,
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        host: { 'class': 'bb-dialog-header' },
        styles: [".bb-dialog-header{display:-ms-flexbox;display:flex;min-height:60px;-ms-flex-direction:column;flex-direction:column;-ms-flex-pack:center;justify-content:center;background-color:#fff;border-top-left-radius:4px;border-top-right-radius:4px;border-bottom:1px solid #d8d8d8}.bb-dialog-header .bb-dialog-header-content,.bb-dialog-header .bb-dialog-header-content h1{max-width:100%;font-size:20px;font-weight:500;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.bb-dialog-header-navigation,.bb-dialog-header-row{width:100%;display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}.bb-dialog-header-row{padding:10px 20px}.bb-dialog-header-navigation{width:100%;padding:0 20px;overflow-x:auto;white-space:nowrap}.bb-dialog-header-navigation:empty{margin:0;height:0;padding:0;visibility:hidden}.bb-dialog-header-content{-ms-flex:1;flex:1}.bb-dialog-header-icon{width:40px;height:40px;display:-ms-flexbox;display:flex;min-width:40px;overflow:hidden;min-height:40px;margin-right:10px;border-radius:50%;position:relative;-ms-flex-align:center;align-items:center;-ms-flex-pack:center;justify-content:center}.bb-dialog-header-icon:after{top:0;left:0;right:0;bottom:0;content:\"\";opacity:.14;position:absolute;background-color:currentColor}.bb-dialog-header-close{width:32px;height:32px;border:none;min-width:32px;min-height:32px;overflow:hidden;margin-left:10px;border-radius:4px;position:relative;margin-right:-10px;display:inline-block;background-color:transparent}.bb-dialog-header-close:after,.bb-dialog-header-close:before{top:50%;left:20%;width:60%;height:2px;content:\"\";margin-top:-1px;position:absolute;background-color:#a2a9ba}.bb-dialog-header-close:before{-ms-transform:rotate(45deg);transform:rotate(45deg)}.bb-dialog-header-close:after{-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.bb-dialog-header-close:hover{background-color:rgba(0,0,0,.08)}.bb-dialog-header-close:focus{background-color:rgba(0,0,0,.12)}.bb-dialog-header-close:active{background-color:rgba(0,0,0,.16)}"]
    })
], BbDialogHeader);

let BbDialogLink = class BbDialogLink {
};
BbDialogLink = __decorate([
    Component({
        selector: '[bb-dialog-link]',
        template: "<ng-content></ng-content>\r\n",
        changeDetection: ChangeDetectionStrategy.OnPush,
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        host: { 'class': 'bb-dialog-link' },
        styles: [".bb-dialog-link{height:30px;display:-ms-flexbox;display:flex;font-size:16px;font-weight:500;white-space:nowrap;-ms-flex-align:center;align-items:center;color:#6b5c5c!important;background-color:transparent;text-decoration:none!important;border-bottom:2px solid transparent}.bb-dialog-link+.bb-dialog-link{margin-left:10px}.bb-dialog-link:hover:not(.disabled){border-bottom:2px solid rgba(117,119,148,.2)}.bb-dialog-link.active,.bb-dialog-link.active:hover{color:#5b53ff!important;border-bottom-color:#5b53ff}.bb-dialog-link.disabled,.bb-dialog-link.disabled:active,.bb-dialog-link.disabled:focus,.bb-dialog-link.disabled:hover{opacity:.4;cursor:default;box-shadow:none}"]
    })
], BbDialogLink);

let BbDialogActions = class BbDialogActions {
};
BbDialogActions = __decorate([
    Component({
        selector: '[bb-dialog-actions]',
        template: "<bb-form-group class=\"end\">\r\n    <ng-content></ng-content>\r\n</bb-form-group>\r\n",
        changeDetection: ChangeDetectionStrategy.OnPush,
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        host: { 'class': 'bb-dialog-actions' },
        styles: [".bb-dialog-actions{padding:20px;display:block;background-color:#fff;border-top:1px solid #d8d8d8;border-bottom-left-radius:4px;border-bottom-right-radius:4px}"]
    })
], BbDialogActions);

let BbDialogInsertion = class BbDialogInsertion {
    constructor(viewContainerRef) {
        this.viewContainerRef = viewContainerRef;
    }
};
BbDialogInsertion.ctorParameters = () => [
    { type: ViewContainerRef }
];
BbDialogInsertion = __decorate([
    Directive({
        selector: '[bbDialogInsertion]'
    })
], BbDialogInsertion);

let BbDialogContainer = class BbDialogContainer {
    constructor(_elementRef, _changeDetection, _componentFactoryResolver) {
        this._elementRef = _elementRef;
        this._changeDetection = _changeDetection;
        this._componentFactoryResolver = _componentFactoryResolver;
        // Data.
        this.componentRef = null;
        this.childComponentType = null;
        // State.
        this.overlayClicked$ = new Subject();
    }
    get onOverlayClicked() {
        return this.overlayClicked$.pipe(take(1));
    }
    ngAfterViewInit() {
        // Load the child component.
        this.loadChildComponent(this.childComponentType);
        // Listen for mouse click on the dialog container.
        this.listenForClicks();
        // Detect changes to notify change detection.
        this._changeDetection.detectChanges();
    }
    ngOnDestroy() {
        this._subscription && this._subscription.unsubscribe();
    }
    onAnimationDone(event) {
        // Check if the dialog is being destroyed.
        if (event.toState !== 'void') {
            return;
        }
        // Destroy the ref if it exists.
        this.componentRef && this.componentRef.destroy();
    }
    listenForClicks() {
        if (!this._elementRef || !this._elementRef.nativeElement) {
            return;
        }
        const mouseDown$ = fromEvent(this._elementRef.nativeElement, 'mousedown');
        const touchStart$ = fromEvent(this._elementRef.nativeElement, 'touchstart');
        const start$ = race([mouseDown$, touchStart$]);
        const mouseUp$ = fromEvent(this._elementRef.nativeElement, 'mouseup');
        const touchEnd$ = fromEvent(this._elementRef.nativeElement, 'touchend');
        const end$ = race([mouseUp$, touchEnd$]);
        this._subscription = start$.pipe(switchMap(() => end$)).subscribe(() => {
            this.overlayClicked$.next();
        });
    }
    loadChildComponent(componentType) {
        // Resolve the component.
        const componentFactory = this._componentFactoryResolver.resolveComponentFactory(componentType);
        // Get the view container ref and clear it.
        const viewContainerRef = this.insertion.viewContainerRef;
        viewContainerRef.clear();
        // Create an instance of the component.
        this.componentRef = viewContainerRef.createComponent(componentFactory);
    }
};
BbDialogContainer.ctorParameters = () => [
    { type: ElementRef },
    { type: ChangeDetectorRef },
    { type: ComponentFactoryResolver }
];
__decorate([
    ViewChild(BbDialogInsertion, { static: true })
], BbDialogContainer.prototype, "insertion", void 0);
__decorate([
    HostListener('@bbDialogAnimation.done', ['$event'])
], BbDialogContainer.prototype, "onAnimationDone", null);
BbDialogContainer = __decorate([
    Component({
        selector: 'bb-dialog-container',
        template: "<div class=\"bb-dialog-container-backdrop\">\r\n</div>\r\n\r\n<div class=\"bb-dialog-container-component\">\r\n    <ng-container bbDialogInsertion>\r\n    </ng-container>\r\n</div>\r\n",
        changeDetection: ChangeDetectionStrategy.OnPush,
        encapsulation: ViewEncapsulation.None,
        host: { 'class': 'bb-dialog-container', '[@bbDialogAnimation]': 'true' },
        preserveWhitespaces: false,
        animations: [
            trigger('bbDialogAnimation', [
                transition(':enter', [
                    group([
                        query('.bb-dialog-container-backdrop', [
                            style({
                                opacity: 0
                            }),
                            animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({
                                opacity: 1
                            }))
                        ]),
                        query('.bb-dialog-container-component', [
                            style({
                                transform: 'scale(0.95)'
                            }),
                            animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({
                                transform: 'scale(1)'
                            }))
                        ])
                    ])
                ]),
                transition(':leave', [
                    group([
                        query('.bb-dialog-container-backdrop', [
                            animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({
                                opacity: 0
                            }))
                        ]),
                        query('.bb-dialog-container-component', [
                            animate('150ms cubic-bezier(0, 0, 0.2, 1)', style({
                                opacity: 0,
                                transform: 'scale(0.95)'
                            }))
                        ])
                    ])
                ])
            ])
        ],
        styles: [".bb-dialog-container,.bb-dialog-container-backdrop{top:0;left:0;right:0;bottom:0;z-index:1000;position:fixed}.bb-dialog-container{display:-ms-flexbox;display:flex}.bb-dialog-container-backdrop{background-color:rgba(0,0,0,.5)}.bb-dialog-container-component{width:100%;margin:auto;padding:20px;z-index:1001;display:block}"]
    })
], BbDialogContainer);

let nextUniqueId = 0;
let BbDialogConfirm = class BbDialogConfirm {
    constructor(config, dialogRef) {
        this.config = config;
        this.dialogRef = dialogRef;
        // Id.
        this.dialogId = `bb-dialog-confirm-${nextUniqueId++}`;
    }
    ngAfterViewInit() {
        // Initial focus the button.
        this.confirmButton.focus();
    }
    onClose(result) {
        this.dialogRef.close(result);
    }
};
BbDialogConfirm.ctorParameters = () => [
    { type: BbDialogConfig },
    { type: BbDialogRef }
];
__decorate([
    ViewChild('confirm', { read: BbButton })
], BbDialogConfirm.prototype, "confirmButton", void 0);
BbDialogConfirm = __decorate([
    Component({
        selector: 'bb-dialog-confirm',
        template: "<div [attr.aria-labelledby]=\"dialogId\"\r\n     bb-dialog-modal\r\n     bbFocusTrap>\r\n    <header bb-dialog-header>\r\n        <h1 *ngIf=\"config?.data?.title as title\"\r\n            [id]=\"dialogId\">\r\n            {{ title | bbLocalize:{optional: true} }}\r\n        </h1>\r\n    </header>\r\n\r\n    <p>\r\n        {{ config?.data?.description | bbLocalize:{optional: true} }}\r\n    </p>\r\n\r\n    <footer bb-dialog-actions>\r\n        <button *ngIf=\"config?.data?.cancelButtonText as cancelButtonText\"\r\n                (click)=\"onClose(false)\"\r\n                bb-button\r\n                type=\"button\">\r\n            {{ cancelButtonText | bbLocalize:{optional: true} }}\r\n        </button>\r\n        <button #confirm\r\n                *ngIf=\"config?.data?.confirmButtonText as confirmButtonText\"\r\n                (click)=\"onClose(true)\"\r\n                bb-button\r\n                type=\"button\"\r\n                class=\"destructive\">\r\n            {{ confirmButtonText | bbLocalize:{optional: true} }}\r\n        </button>\r\n    </footer>\r\n</div>\r\n",
        changeDetection: ChangeDetectionStrategy.OnPush,
        encapsulation: ViewEncapsulation.None,
        preserveWhitespaces: false,
        host: { 'class': 'bb-dialog-confirm' },
        styles: [".bb-dialog-confirm{display:block}"]
    })
], BbDialogConfirm);

class BbDialogInjector {
    constructor(_parentInjector, _additionalTokens) {
        this._parentInjector = _parentInjector;
        this._additionalTokens = _additionalTokens;
    }
    get(token, notFoundValue) {
        // First check if the additional token
        // contains the token.
        const value = this._additionalTokens.get(token);
        // If that value exists return it.
        if (value) {
            return value;
        }
        // Else query the parent injector.
        return this._parentInjector.get(token, notFoundValue);
    }
}

let Dialog = class Dialog {
    constructor(_injector, _applicationRef, _componentFactoryResolver) {
        this._injector = _injector;
        this._applicationRef = _applicationRef;
        this._componentFactoryResolver = _componentFactoryResolver;
    }
    open(componentType, config) {
        return this.createDialog(componentType, config);
    }
    confirm(title, description, options = {}) {
        return this.open(BbDialogConfirm, {
            data: {
                title,
                description,
                cancelButtonText: options.cancelButtonText || 'dialog.default_cancel_button',
                confirmButtonText: options.confirmButtonText || 'dialog.default_confirm_button'
            }
        });
    }
    createDialog(componentType, config) {
        // Create a reference.
        const dialogRef = new BbDialogRef();
        // Create a map with the config.
        const map = new WeakMap();
        map.set(BbDialogConfig, config);
        map.set(BbDialogRef, dialogRef);
        // Create a custom injector.
        const dialogInjector = new BbDialogInjector(this._injector, map);
        // Resolve the dialog component reference.
        const dialogComponentRef = this._componentFactoryResolver
            .resolveComponentFactory(BbDialogContainer)
            .create(dialogInjector);
        // Attach the host view to the application.
        this._applicationRef.attachView(dialogComponentRef.hostView);
        try {
            // Remove the current focus.
            const activeElement = document.activeElement;
            activeElement.blur();
            // Append the element to the DOM.
            document.body.appendChild(dialogComponentRef.location.nativeElement);
        }
        catch (_a) {
            // Don't do anything, because it must've failed.
        }
        // Set the child component type on the component.
        dialogComponentRef.instance.childComponentType = componentType;
        dialogComponentRef.instance.onOverlayClicked.subscribe(() => dialogRef.onOverlayClicked());
        // Listen for close events.
        dialogRef.afterClosed.subscribe(() => this.deleteDialog(dialogComponentRef));
        // Return the reference.
        return dialogRef;
    }
    deleteDialog(dialogComponentRef) {
        // Only continue if the dialog component ref exists.
        if (!dialogComponentRef) {
            return;
        }
        // Detach the dialog.
        this._applicationRef.detachView(dialogComponentRef.hostView);
        // Destroy the dialog.
        dialogComponentRef.destroy();
        dialogComponentRef = null;
    }
};
Dialog.ctorParameters = () => [
    { type: Injector },
    { type: ApplicationRef },
    { type: ComponentFactoryResolver }
];
Dialog = __decorate([
    Injectable()
], Dialog);

var DialogModule_1;
let DialogModule = DialogModule_1 = class DialogModule {
    static forRoot() {
        return {
            ngModule: DialogModule_1,
            providers: [Dialog]
        };
    }
};
DialogModule = DialogModule_1 = __decorate([
    NgModule({
        imports: [
            CommonModule,
            LocalizeModule,
            ElementsModule
        ],
        declarations: [
            BbDialogContainer,
            BbDialogOverlay,
            BbDialogModal,
            BbDialogHeader,
            BbDialogLink,
            BbDialogActions,
            BbDialogConfirm,
            BbDialogInsertion
        ],
        entryComponents: [
            BbDialogContainer,
            BbDialogConfirm
        ],
        exports: [
            BbDialogOverlay,
            BbDialogModal,
            BbDialogHeader,
            BbDialogLink,
            BbDialogActions
        ]
    })
], DialogModule);

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

export { BbDialogActions, BbDialogConfig, BbDialogHeader, BbDialogLink, BbDialogModal, BbDialogOverlay, BbDialogRef, Dialog, DialogModule, BbDialogContainer as ɵa, BbDialogInsertion as ɵb, BbDialogConfirm as ɵc };
//# sourceMappingURL=bravobit-bb-foundation-dialog.js.map
