import { ChangeDetectionStrategy , ChangeDetectorRef , Component , ComponentFactory , ComponentFactoryResolver , ComponentRef , EventEmitter , HostBinding , Injector , Type , ViewChild , ViewContainerRef , } from '@angular/core' ; import { Observable , Subscription } from 'rxjs' ; import { DynamicHostDirective } from '../../../../common/directives/dynamic-host.directive' ; interface DismissIntentAbleComponent { dismissIntent : EventEmitter < any > ; } /**
 * Popup component. It should be used as a singleton component in the root element. It relies on Popup Service
 * for inter-component communication.
 */ @ Component ( { selector : 'm-composer__popup' , changeDetection : ChangeDetectionStrategy . OnPush , templateUrl : 'popup.component.html' , } ) export class PopupComponent { /**
     * Is the popup open and shown?
     */ @ HostBinding ( 'class.m-composer__popup--open' ) open : boolean = false ; /**
     * Placeholder for child component injection
     */ @ ViewChild ( DynamicHostDirective , { static : true } ) protected host : DynamicHostDirective ; /**
     * Injected component's ref
     */ protected componentRef : ComponentRef < unknown > ; /**
     * Current popup execution scope
     */ protected current : Observable < any > ; constructor ( protected cd , protected componentFactoryResolver ) { } param component param injector create < C extends DismissIntentAbleComponent > ( component , injector ) { this . dismiss ( ) ; if ( ! component ) { throw new Error ( 'Invalid component class' ) ; } const componentFactory = this . componentFactoryResolver . resolveComponentFactory ( component ) ; const viewContainerRef = this . host . viewContainerRef ; viewContainerRef . clear ( ) ; const componentRef = viewContainerRef . createComponent ( componentFactory , void 0 , injector ) ; this . current = new Observable ( subscriber => { try { if ( ! componentRef . instance . dismissIntent ) { throw new Error ( 'Component instance is missing required `dismissIntent` EventEmitter' ) ; } else if ( ! ( componentRef . instance . dismissIntent instanceof EventEmitter ) ) { throw new Error ( 'Component instance `dismissIntent` is not an EventEmitter' ) ; } else { this . open = true ; this . detectChanges ( ) ; const dismissIntentSubscription = componentRef . instance . dismissIntent . subscribe ( payload => { try { subscriber . next ( payload ) ; subscriber . complete ( ) ; this . dismiss ( ) ; } catch ( e ) { subscriber . error ( e ) ; this . dismiss ( ) ; } } ) ; return ( ) => { try { dismissIntentSubscription . unsubscribe ( ) ; this . dismiss ( ) ; } catch ( e ) { console . warn ( 'PopupComponent.present.$.unsubscribe' , e ) ; } } ; } } catch ( e ) { console . warn ( 'PopupComponent.present.$' , e ) ; subscriber . error ( e ) ; this . dismiss ( ) ; } } ) ; this . componentRef = componentRef ; return this ; } /**
     * Returns the popup modal execution scope. The popup is managed by a COLD observable, so it'll
     * open as soon as something subscribes to it.
     *
     * Pro tip: .present().toPromise() shows it immediately.
     */ present < C > ( ) { if ( ! this . componentRef ) { throw new Error ( 'Invalid component ref' ) ; } return this . current ; } /**
     * Hides the popup modal, without destroying it
     */ hide ( ) { this . open = false ; this . detectChanges ( ) ; } /**
     * Dismisses and destroys the modal, frees all resources. But... ensure your component unsubscribes!
     */ dismiss ( kill = false ) { if ( ! kill ) { this . hide ( ) ; } if ( this . componentRef ) { this . componentRef . destroy ( ) ; this . componentRef = void 0 ; } this . current = void 0 ; this . host . viewContainerRef . clear ( ) ; } /**
     * Detects changes
     */ detectChanges ( ) { this . cd . markForCheck ( ) ; this . cd . detectChanges ( ) ; } }