UNPKG

mk-magic-alerts

Version:
256 lines (243 loc) 17.3 kB
import * as i0 from '@angular/core'; import { Pipe, Injectable, Input, Component, createComponent } from '@angular/core'; import { AsyncPipe } from '@angular/common'; import { BehaviorSubject, auditTime, Subject, fromEvent, timer, race } from 'rxjs'; import { takeUntil, repeat, first, tap } from 'rxjs/operators'; import { trigger, state, transition, style, sequence, query, animate, group } from '@angular/animations'; const AlertState = { DISPLAY: 'display', DISMISS: 'dismiss', DISMISSED: 'dismissed', }; class NewlineAndTabsPipe { transform(value) { return value?.toString().replace(/(?:\r\n|\r|\n)/g, '<br />').replace(/(?:\t)/g, '&nbsp;&nbsp;&nbsp;&nbsp;') ?? ''; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: NewlineAndTabsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); } static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "20.0.3", ngImport: i0, type: NewlineAndTabsPipe, isStandalone: true, name: "newlineAndTabs" }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: NewlineAndTabsPipe, decorators: [{ type: Pipe, args: [{ name: 'newlineAndTabs', standalone: true }] }] }); const alertAnimations = [ trigger('state', [ state('void', style({ height: '0', width: '0', 'padding-top': '0', 'padding-bottom': '0', 'margin-top': '5px', 'margin-bottom': '0', opacity: '0', })), state(AlertState.DISPLAY, style({ height: '*', 'padding-top': '*', 'padding-bottom': '*', 'margin-top': '5px', 'margin-bottom': '0', })), state(AlertState.DISMISS, style({ height: '0', width: '0', 'padding-top': '0', 'padding-bottom': '0', 'margin-top': '5px', 'margin-bottom': '0', 'border-width': '0', opacity: '0', })), state(AlertState.DISMISSED, style({ height: '0', width: '0', 'padding-top': '0', 'padding-bottom': '0', 'margin-top': '0', 'margin-bottom': '0', 'border-width': '0', opacity: '0', })), transition('* => display', // sequence = sequential actions: sequence([ query('.alert-text', [style({ opacity: 0 })]), animate('0.3s ease'), query('.alert-text', [animate('0.1s', style({ opacity: 1 }))]) ])), transition('display => dismiss', // group = parallel actions: group([ query('.alert-text', [animate('0.05s', style({ opacity: 0 }))]), animate('0.5s ease') ])), transition('dismiss => dismissed', // group = parallel actions: group([ query('.alert-text', [animate('0.05s', style({ opacity: 0 }))]), animate('0.3s ease') ])) ]) ]; class Alert { constructor(text, type, dismissTime) { this.text = text; this.type = type; this.dismissTimeInMillis = dismissTime; this.state = AlertState.DISPLAY; } } class AlertsStore { constructor() { this.alertsSubject = new BehaviorSubject([]); // Added 'auditTime(100)' to prevent error 'NG0100: Expression has changed after it was checked' this.alerts$ = this.alertsSubject.asObservable().pipe(auditTime(100)); this.dismissAllSubject = new Subject(); this.dismissAll$ = this.dismissAllSubject.asObservable(); } dismissAll() { this.dismissAllSubject.next(); } addAlert(text, type, dismissTime) { // Remove already dismissed alerts // filter() makes a shallow copy of the array (a new array, but pointing to the same objects) const activeAlerts = this.alertsSubject.getValue().filter((m) => m.state !== AlertState.DISMISSED); // Create and add new message: activeAlerts.push(new Alert(text, type, dismissTime)); // Trigger Observable to display alerts: this.alertsSubject.next(activeAlerts); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertsStore, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertsStore, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertsStore, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); class AlertComponent { constructor(elementRef, alertsStore, cdRef) { this.elementRef = elementRef; this.alertsStore = alertsStore; this.cdRef = cdRef; this.dismissTimeInMillis = 2_147_483_647; this.destroy$ = new Subject(); } ngOnInit() { const mouseenter$ = fromEvent(this.elementRef.nativeElement, 'mouseenter'); const mouseleave$ = fromEvent(this.elementRef.nativeElement, 'mouseleave'); // Observable that allows closing of the alert by user-click: const dismissalByUser$ = fromEvent(this.elementRef.nativeElement, 'mouseup'); // If dismissal is requested programmatically from alerts-service: const dismissalByService$ = this.alertsStore.dismissAll$; // Observable that closes the alert after a given time, // unless user hovers over the alert with a cursor => 'takeUntil()' and 'repeat()' const dismissalAfterTimeout$ = timer(this.dismissTimeInMillis).pipe(takeUntil(mouseenter$), repeat({ delay: () => mouseleave$ })); // on mouseleave: Resubscribe to source (here: 'timer()') race([dismissalByUser$, dismissalByService$, dismissalAfterTimeout$]) .pipe(first(), // after first emission, unsubscribe also from the winning observable tap(() => this.setDismissalStart()), takeUntil(this.destroy$)) .subscribe(); } /* Triggers the animated disappearing of the alert */ setDismissalStart() { this.alertParams.state = AlertState.DISMISS; this.cdRef.detectChanges(); } /* Is evoked at the end of the animated disappearing of the alert */ onDismissalCompleted(event) { if (event.fromState === AlertState.DISPLAY && event.toState === AlertState.DISMISS) { this.alertParams.state = AlertState.DISMISSED; this.cdRef.detectChanges(); } } ngOnDestroy() { this.destroy$.next(); this.destroy$.unsubscribe(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertComponent, deps: [{ token: i0.ElementRef }, { token: AlertsStore }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.3", type: AlertComponent, isStandalone: true, selector: "app-alert", inputs: { alertParams: "alertParams", dismissTimeInMillis: "dismissTimeInMillis" }, ngImport: i0, template: "@if (alertParams) {\n\t<div class=\"clickable-area\">\n\t\t<div class=\"alert-container alert-{{ alertParams.type }}\" [@state]=\"alertParams.state\" (@state.done)=\"onDismissalCompleted($event)\">\n\t\t\t\n\t\t\t<div class=\"alert-text\" [innerHtml]=\"alertParams.text | newlineAndTabs\"></div>\n\t\n\t\t\t<div class=\"btn-dismiss\">\n\t\t\t\t<i class=\"fa fa-times\"></i>\n\t\t\t</div>\n\t\n\t\t</div>\n\t</div>\n}\n", styles: [".clickable-area{cursor:pointer}.clickable-area .alert-container{position:relative;padding:5px 15px;margin:0;border-radius:4px;border-width:1px;border-style:solid;overflow:hidden;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014;z-index:1020!important;display:flex;justify-content:space-between;align-items:center}.clickable-area .alert-container .alert-text{font:400 16px/20px Roboto}.clickable-area .alert-container .btn-dismiss{align-self:flex-start;margin-top:1px}.clickable-area .alert-info{color:#004085;border-color:#004085;background-color:#b8daff}.clickable-area .alert-info .btn-dismiss:hover{text-shadow:0 0 10px #3366ff,0 0 20px #3366ff}.clickable-area .alert-success{color:#155724;border-color:#155724;background-color:#c3e6cb}.clickable-area .alert-success .btn-dismiss:hover{text-shadow:0 0 10px #30a24d,0 0 20px #30a24d}.clickable-area .alert-warning{color:#856404;border-color:#856404;background-color:#ffeeba}.clickable-area .alert-warning .btn-dismiss:hover{text-shadow:0 0 10px #b38600,0 0 20px #b38600}.clickable-area .alert-error{color:#721c24;border-color:#721c24;background-color:#f8d7da}.clickable-area .alert-error .btn-dismiss:hover{text-shadow:0 0 10px #ff4c59,0 0 20px #ff4c59}\n"], dependencies: [{ kind: "pipe", type: NewlineAndTabsPipe, name: "newlineAndTabs" }], animations: alertAnimations }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertComponent, decorators: [{ type: Component, args: [{ selector: 'app-alert', animations: alertAnimations, imports: [NewlineAndTabsPipe], template: "@if (alertParams) {\n\t<div class=\"clickable-area\">\n\t\t<div class=\"alert-container alert-{{ alertParams.type }}\" [@state]=\"alertParams.state\" (@state.done)=\"onDismissalCompleted($event)\">\n\t\t\t\n\t\t\t<div class=\"alert-text\" [innerHtml]=\"alertParams.text | newlineAndTabs\"></div>\n\t\n\t\t\t<div class=\"btn-dismiss\">\n\t\t\t\t<i class=\"fa fa-times\"></i>\n\t\t\t</div>\n\t\n\t\t</div>\n\t</div>\n}\n", styles: [".clickable-area{cursor:pointer}.clickable-area .alert-container{position:relative;padding:5px 15px;margin:0;border-radius:4px;border-width:1px;border-style:solid;overflow:hidden;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014;z-index:1020!important;display:flex;justify-content:space-between;align-items:center}.clickable-area .alert-container .alert-text{font:400 16px/20px Roboto}.clickable-area .alert-container .btn-dismiss{align-self:flex-start;margin-top:1px}.clickable-area .alert-info{color:#004085;border-color:#004085;background-color:#b8daff}.clickable-area .alert-info .btn-dismiss:hover{text-shadow:0 0 10px #3366ff,0 0 20px #3366ff}.clickable-area .alert-success{color:#155724;border-color:#155724;background-color:#c3e6cb}.clickable-area .alert-success .btn-dismiss:hover{text-shadow:0 0 10px #30a24d,0 0 20px #30a24d}.clickable-area .alert-warning{color:#856404;border-color:#856404;background-color:#ffeeba}.clickable-area .alert-warning .btn-dismiss:hover{text-shadow:0 0 10px #b38600,0 0 20px #b38600}.clickable-area .alert-error{color:#721c24;border-color:#721c24;background-color:#f8d7da}.clickable-area .alert-error .btn-dismiss:hover{text-shadow:0 0 10px #ff4c59,0 0 20px #ff4c59}\n"] }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: AlertsStore }, { type: i0.ChangeDetectorRef }], propDecorators: { alertParams: [{ type: Input, args: [{ required: true }] }], dismissTimeInMillis: [{ type: Input }] } }); class AlertsComponent { constructor(alertsStore) { this.alertsStore = alertsStore; this.alerts$ = this.alertsStore.alerts$; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertsComponent, deps: [{ token: AlertsStore }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.0.3", type: AlertsComponent, isStandalone: true, selector: "magic-alerts", ngImport: i0, template: "\n\n<link href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap\" rel=\"stylesheet\">\n<link href=\"https://use.fontawesome.com/releases/v5.3.1/css/all.css\" rel=\"stylesheet\" integrity=\"sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU\" crossorigin=\"anonymous\">\n\n<!-- Alerts Container -->\n<div id=\"mk-magic-messages\" class=\"alerts-container\">\n\t@for(alertParams of alerts$ | async; track alertParams) {\n\t\t<app-alert\n\t\t\t[alertParams]=\"alertParams\"\n\t\t\t[dismissTimeInMillis]=\"alertParams.dismissTimeInMillis\">\n\t\t</app-alert>\n\t}\n</div>", styles: ["#mk-magic-messages.alerts-container{position:fixed;top:0;left:15px;right:15px;z-index:20000}@media (min-width: 768px){#mk-magic-messages.alerts-container{left:10%;right:10%}}@media (min-width: 992px){#mk-magic-messages.alerts-container{left:20%;right:20%}}@media (min-width: 1200px){#mk-magic-messages.alerts-container{left:25%;right:25%}}@media (min-width: 1500px){#mk-magic-messages.alerts-container{left:30%;right:30%}}\n"], dependencies: [{ kind: "component", type: AlertComponent, selector: "app-alert", inputs: ["alertParams", "dismissTimeInMillis"] }, { kind: "pipe", type: AsyncPipe, name: "async" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertsComponent, decorators: [{ type: Component, args: [{ selector: 'magic-alerts', imports: [AlertComponent, AsyncPipe], template: "\n\n<link href=\"https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap\" rel=\"stylesheet\">\n<link href=\"https://use.fontawesome.com/releases/v5.3.1/css/all.css\" rel=\"stylesheet\" integrity=\"sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU\" crossorigin=\"anonymous\">\n\n<!-- Alerts Container -->\n<div id=\"mk-magic-messages\" class=\"alerts-container\">\n\t@for(alertParams of alerts$ | async; track alertParams) {\n\t\t<app-alert\n\t\t\t[alertParams]=\"alertParams\"\n\t\t\t[dismissTimeInMillis]=\"alertParams.dismissTimeInMillis\">\n\t\t</app-alert>\n\t}\n</div>", styles: ["#mk-magic-messages.alerts-container{position:fixed;top:0;left:15px;right:15px;z-index:20000}@media (min-width: 768px){#mk-magic-messages.alerts-container{left:10%;right:10%}}@media (min-width: 992px){#mk-magic-messages.alerts-container{left:20%;right:20%}}@media (min-width: 1200px){#mk-magic-messages.alerts-container{left:25%;right:25%}}@media (min-width: 1500px){#mk-magic-messages.alerts-container{left:30%;right:30%}}\n"] }] }], ctorParameters: () => [{ type: AlertsStore }] }); class AlertsService { constructor(alertsStore, applicationRef, injector) { this.alertsStore = alertsStore; this.applicationRef = applicationRef; this.injector = injector; this.initializeAlertsComponent(); } initializeAlertsComponent() { // Create a div element and append it to the document body const hostElement = document.createElement('div'); document.body.appendChild(hostElement); // Create AlertsComponent and attach it to the DOM this.alertsComponentRef = createComponent(AlertsComponent, { hostElement, environmentInjector: this.applicationRef.injector, elementInjector: this.injector }); // Attach the AlertsComponent to the application this.applicationRef.attachView(this.alertsComponentRef.hostView); } showInfo(text, dismissTimeInMillis = 10_000) { this.alertsStore.addAlert(text, 'info', dismissTimeInMillis); } showSuccess(text, dismissTimeInMillis = 4_000) { this.alertsStore.addAlert(text, 'success', dismissTimeInMillis); } showWarning(text, dismissTimeInMillis = 10_000) { this.alertsStore.addAlert(text, 'warning', dismissTimeInMillis); } showError(text, dismissTimeInMillis = 2_147_483_647) { this.alertsStore.addAlert(text, 'error', dismissTimeInMillis); } clear() { this.alertsStore.dismissAll(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertsService, deps: [{ token: AlertsStore }, { token: i0.ApplicationRef }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertsService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.3", ngImport: i0, type: AlertsService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: () => [{ type: AlertsStore }, { type: i0.ApplicationRef }, { type: i0.Injector }] }); class MockAlertsService { showInfo(text, dismissTimeInMillis = 10_000) { } showSuccess(text, dismissTimeInMillis = 4_000) { } showWarning(text, dismissTimeInMillis = 10_000) { } showError(text, dismissTimeInMillis = 2_147_483_647) { } clear() { } } /* * Public API Surface of mk-magic-alerts */ /** * Generated bundle index. Do not edit. */ export { AlertsService, MockAlertsService }; //# sourceMappingURL=mk-magic-alerts.mjs.map