mk-magic-alerts
Version:
Flying in alerts for Angular applications
306 lines (292 loc) • 42.5 kB
JavaScript
import * as i0 from '@angular/core';
import { Service, Pipe, inject, ElementRef, DestroyRef, input, viewChild, signal, computed, ChangeDetectionStrategy, Component, InjectionToken, makeEnvironmentProviders, ApplicationRef, Injector, createComponent } from '@angular/core';
import { toSignal, takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { BehaviorSubject, Subject, fromEvent, timer, race } from 'rxjs';
import { takeUntil, repeat, take, tap } from 'rxjs/operators';
const AlertState = {
DISPLAY: 'display',
DISMISS: 'dismiss',
DISMISSED: 'dismissed',
};
class AlertsStore {
constructor() {
this.alertsSubject = new BehaviorSubject([]);
this.nextAlertId = 1;
this.alerts = toSignal(this.alertsSubject.asObservable(), {
initialValue: [],
manualCleanup: true
});
this.dismissAllSubject = new Subject();
this.dismissAll$ = this.dismissAllSubject.asObservable();
}
dismissAll() {
this.dismissAllSubject.next();
}
addAlert(text, type, dismissTimeInMillis) {
// Remove alerts that already started or finished their exit animation.
// filter() makes a shallow copy of the array (a new array, but pointing to the same objects)
const activeAlerts = this.alertsSubject
.getValue()
.filter((alert) => alert.state === AlertState.DISPLAY);
// Create and add new message:
this.alertsSubject.next([
...activeAlerts,
this.createAlert(text, type, dismissTimeInMillis)
]);
}
createAlert(text, type, dismissTimeInMillis) {
return {
id: `alert-${this.nextAlertId++}`,
text,
type,
dismissTimeInMillis,
state: AlertState.DISPLAY
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AlertsStore, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.0", ngImport: i0, type: AlertsStore }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AlertsStore, decorators: [{
type: Service
}] });
class NewlineAndTabsPipe {
transform(value) {
return value?.toString().replace(/(?:\r\n|\r|\n)/g, '<br />').replace(/(?:\t)/g, ' ') ?? '';
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: NewlineAndTabsPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "22.0.0", ngImport: i0, type: NewlineAndTabsPipe, isStandalone: true, name: "newlineAndTabs" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: NewlineAndTabsPipe, decorators: [{
type: Pipe,
args: [{
name: 'newlineAndTabs',
standalone: true
}]
}] });
const AlertEntryAnimation = {
DOT: 'dot',
BURST: 'burst',
DROP: 'drop',
SLIDE_LEFT: 'slide-left',
SLIDE_RIGHT: 'slide-right',
UNFOLD: 'unfold'
};
const AlertAppearance = {
CLASSIC: 'classic',
GRADIENT: 'gradient'
};
class AlertComponent {
constructor() {
this.elementRef = inject((ElementRef));
this.alertsStore = inject(AlertsStore);
this.destroyRef = inject(DestroyRef);
this.alertParams = input.required(/* @ts-ignore */
...(ngDevMode ? [{ debugName: "alertParams" }] : /* istanbul ignore next */ []));
this.entryAnimation = input.required(/* @ts-ignore */
...(ngDevMode ? [{ debugName: "entryAnimation" }] : /* istanbul ignore next */ []));
this.alertAppearance = input.required(/* @ts-ignore */
...(ngDevMode ? [{ debugName: "alertAppearance" }] : /* istanbul ignore next */ []));
this.container = viewChild('container', /* @ts-ignore */
...(ngDevMode ? [{ debugName: "container" }] : /* istanbul ignore next */ []));
this.state = signal(AlertState.DISPLAY, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
this.fixedEntryAnimation = signal(AlertEntryAnimation.DOT, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "fixedEntryAnimation" }] : /* istanbul ignore next */ []));
this.fixedAlertAppearance = signal(AlertAppearance.CLASSIC, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "fixedAlertAppearance" }] : /* istanbul ignore next */ []));
this.entryAnimationDone = signal(false, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "entryAnimationDone" }] : /* istanbul ignore next */ []));
this.isRendered = computed(() => this.state() !== AlertState.DISMISSED, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "isRendered" }] : /* istanbul ignore next */ []));
this.dismissTimeInMillis = computed(() => this.alertParams().dismissTimeInMillis, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "dismissTimeInMillis" }] : /* istanbul ignore next */ []));
this.enterAnimationClass = computed(() => `alert-enter-${this.fixedEntryAnimation()}`, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "enterAnimationClass" }] : /* istanbul ignore next */ []));
this.leaveAnimationClass = computed(() => `alert-leave-${this.fixedEntryAnimation()}`, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "leaveAnimationClass" }] : /* istanbul ignore next */ []));
this.animationClass = computed(() => this.state() === AlertState.DISMISS
? this.leaveAnimationClass()
: this.entryAnimationDone()
? ''
: this.enterAnimationClass(), /* @ts-ignore */
...(ngDevMode ? [{ debugName: "animationClass" }] : /* istanbul ignore next */ []));
}
ngOnInit() {
this.fixedEntryAnimation.set(this.entryAnimation());
this.fixedAlertAppearance.set(this.alertAppearance());
const el = this.elementRef.nativeElement;
const mouseenter$ = fromEvent(el, 'mouseenter');
const mouseleave$ = fromEvent(el, 'mouseleave');
// Observable that allows closing of the alert by user-click:
const dismissalByUser$ = fromEvent(el, '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$ }));
race([dismissalByUser$, dismissalByService$, dismissalAfterTimeout$])
.pipe(take(1), tap(() => this.setDismissalStart()), takeUntilDestroyed(this.destroyRef))
.subscribe();
}
/* Triggers the animated disappearing of the alert */
setDismissalStart() {
if (this.state() !== AlertState.DISMISS) {
const el = this.container()?.nativeElement;
if (el) {
// Lock current height via CSS var used by the stylesheet
el.style.setProperty('--h', `${el.offsetHeight}px`);
}
this.alertParams().state = AlertState.DISMISS;
this.state.set(AlertState.DISMISS);
}
}
/** After the leave animation finishes, mark as DISMISSED */
onContainerAnimationEnd(event) {
if (event.target !== this.container()?.nativeElement) {
return;
}
if (this.state() === AlertState.DISMISS) {
this.alertParams().state = AlertState.DISMISSED;
this.state.set(AlertState.DISMISSED);
return;
}
this.entryAnimationDone.set(true);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: AlertComponent, isStandalone: true, selector: "app-alert", inputs: { alertParams: { classPropertyName: "alertParams", publicName: "alertParams", isSignal: true, isRequired: true, transformFunction: null }, entryAnimation: { classPropertyName: "entryAnimation", publicName: "entryAnimation", isSignal: true, isRequired: true, transformFunction: null }, alertAppearance: { classPropertyName: "alertAppearance", publicName: "alertAppearance", isSignal: true, isRequired: true, transformFunction: null } }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (alertParams(); as params) {\n <div class=\"clickable-area\">\n @if (isRendered()) {\n <div\n #container\n class=\"alert-container alert-{{ params.type }} alert-{{ fixedAlertAppearance() }} {{ animationClass() }}\"\n role=\"alert\"\n (animationend)=\"onContainerAnimationEnd($event)\">\n\n <div class=\"alert-icon\" aria-hidden=\"true\">\n @switch (params.type) {\n @case ('info') {\n <i class=\"fa fa-info-circle\"></i>\n }\n @case ('success') {\n <i class=\"fa fa-check\"></i>\n }\n @case ('warning') {\n <i class=\"fa fa-exclamation-triangle\"></i>\n }\n @case ('error') {\n <i class=\"fa fa-exclamation-triangle\"></i>\n }\n }\n </div>\n\n <div class=\"alert-text\" [innerHtml]=\"params.text | newlineAndTabs\"></div>\n\n <button type=\"button\" class=\"btn-dismiss\" aria-label=\"Alert schliessen\">\n <i class=\"fa fa-times\"></i>\n </button>\n </div>\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";.clickable-area{cursor:pointer;margin-top:5px}.clickable-area .alert-container{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:15px;align-items:center;height:var(--h, auto);margin:0;padding:5px 15px;overflow:hidden;border:1px solid;border-radius:4px;z-index:1020!important}.clickable-area .alert-container .alert-icon{display:none}.clickable-area .alert-container .alert-text{min-width:0;overflow-wrap:anywhere;word-break:break-word;font:400 16px/20px Roboto}.clickable-area .alert-container .btn-dismiss{justify-self:end;align-self:baseline;padding:0;border:0;background:transparent;cursor:pointer;font-size:15px}.clickable-area .alert-container.alert-gradient{grid-template-columns:auto minmax(0,1fr) auto;column-gap:12px;padding:10px 10px 10px 14px;border-radius:10px}.clickable-area .alert-container.alert-gradient .alert-icon{align-self:start;display:grid;width:32px;height:32px;place-items:center;border-radius:50%;font-size:16px}.clickable-area .alert-container.alert-gradient .alert-text{font:400 16px/21px Roboto}.clickable-area .alert-container.alert-gradient .btn-dismiss{display:grid;width:28px;height:28px;place-items:center;align-self:start;border-radius:50%;transition:color .16s ease,background-color .16s ease,box-shadow .16s ease}.clickable-area .alert-enter-dot{transform-origin:top left;animation:alert-enter-dot .32s ease both}.clickable-area .alert-enter-dot .alert-text,.clickable-area .alert-enter-dot .alert-icon,.clickable-area .alert-enter-dot .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-dot{height:var(--h, auto);transform-origin:top left;animation:alert-leave-dot .48s ease-in forwards}.clickable-area .alert-leave-dot .alert-text,.clickable-area .alert-leave-dot .alert-icon,.clickable-area .alert-leave-dot .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-burst{transform-origin:center;animation:alert-enter-burst .36s cubic-bezier(.18,1.45,.35,1) both}.clickable-area .alert-enter-burst .alert-text,.clickable-area .alert-enter-burst .alert-icon,.clickable-area .alert-enter-burst .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-burst{height:var(--h, auto);transform-origin:center;animation:alert-leave-burst .42s ease-in forwards}.clickable-area .alert-leave-burst .alert-text,.clickable-area .alert-leave-burst .alert-icon,.clickable-area .alert-leave-burst .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-drop{transform-origin:center top;animation:alert-enter-drop .48s cubic-bezier(.2,1.25,.34,1) both}.clickable-area .alert-enter-drop .alert-text,.clickable-area .alert-enter-drop .alert-icon,.clickable-area .alert-enter-drop .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-drop{height:var(--h, auto);transform-origin:center top;animation:alert-leave-drop .4s ease-in forwards}.clickable-area .alert-leave-drop .alert-text,.clickable-area .alert-leave-drop .alert-icon,.clickable-area .alert-leave-drop .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-slide-right{transform-origin:right center;animation:alert-enter-slide-right .4s cubic-bezier(.22,1,.36,1) both}.clickable-area .alert-enter-slide-right .alert-text,.clickable-area .alert-enter-slide-right .alert-icon,.clickable-area .alert-enter-slide-right .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-slide-right{height:var(--h, auto);transform-origin:right center;animation:alert-leave-slide-right .44s ease-in forwards}.clickable-area .alert-leave-slide-right .alert-text,.clickable-area .alert-leave-slide-right .alert-icon,.clickable-area .alert-leave-slide-right .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-slide-left{transform-origin:left center;animation:alert-enter-slide-left .4s cubic-bezier(.22,1,.36,1) both}.clickable-area .alert-enter-slide-left .alert-text,.clickable-area .alert-enter-slide-left .alert-icon,.clickable-area .alert-enter-slide-left .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-slide-left{height:var(--h, auto);transform-origin:left center;animation:alert-leave-slide-left .44s ease-in forwards}.clickable-area .alert-leave-slide-left .alert-text,.clickable-area .alert-leave-slide-left .alert-icon,.clickable-area .alert-leave-slide-left .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-unfold{transform-origin:center top;animation:alert-enter-unfold .42s cubic-bezier(.22,1,.36,1) both}.clickable-area .alert-enter-unfold .alert-text,.clickable-area .alert-enter-unfold .alert-icon,.clickable-area .alert-enter-unfold .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-unfold{height:var(--h, auto);transform-origin:center top;animation:alert-leave-unfold .44s ease-in forwards}.clickable-area .alert-leave-unfold .alert-text,.clickable-area .alert-leave-unfold .alert-icon,.clickable-area .alert-leave-unfold .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-classic.alert-info{color:#004085;border-color:#004085;background-color:#b8daff;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014}.clickable-area .alert-classic.alert-info .btn-dismiss{color:inherit}.clickable-area .alert-classic.alert-info .btn-dismiss:hover{text-shadow:0 0 10px rgb(51,102,255),0 0 20px rgb(51,102,255)}.clickable-area .alert-classic.alert-success{color:#155724;border-color:#155724;background-color:#c3e6cb;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014}.clickable-area .alert-classic.alert-success .btn-dismiss{color:inherit}.clickable-area .alert-classic.alert-success .btn-dismiss:hover{text-shadow:0 0 10px rgb(48,162,77),0 0 20px rgb(48,162,77)}.clickable-area .alert-classic.alert-warning{color:#856404;border-color:#856404;background-color:#ffeeba;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014}.clickable-area .alert-classic.alert-warning .btn-dismiss{color:inherit}.clickable-area .alert-classic.alert-warning .btn-dismiss:hover{text-shadow:0 0 10px rgb(179,134,0),0 0 20px rgb(179,134,0)}.clickable-area .alert-classic.alert-error{color:#721c24;border-color:#721c24;background-color:#f8d7da;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014}.clickable-area .alert-classic.alert-error .btn-dismiss{color:inherit}.clickable-area .alert-classic.alert-error .btn-dismiss:hover{text-shadow:0 0 10px rgb(255,76,89),0 0 20px rgb(255,76,89)}.clickable-area .alert-gradient.alert-info{color:#004085;border-color:#0040854d;background:linear-gradient(105deg,#daebff,#f4f9ff 68%,#fff);box-shadow:0 5px 12px #0000001a,0 14px 30px #0040851a}.clickable-area .alert-gradient.alert-info .alert-icon{color:#004085;background-color:#c9e2ff}.clickable-area .alert-gradient.alert-info .btn-dismiss{color:#004085}.clickable-area .alert-gradient.alert-info .btn-dismiss:hover{text-shadow:0 0 10px rgb(51,102,255),0 0 20px rgb(51,102,255)}.clickable-area .alert-gradient.alert-success{color:#155724;border-color:#1557244d;background:linear-gradient(105deg,#d8f0dd,#f6fcf7 68%,#fff);box-shadow:0 5px 12px #0000001a,0 14px 30px #1557241a}.clickable-area .alert-gradient.alert-success .alert-icon{color:#155724;background-color:#c9e8d1}.clickable-area .alert-gradient.alert-success .btn-dismiss{color:#155724}.clickable-area .alert-gradient.alert-success .btn-dismiss:hover{text-shadow:0 0 10px rgb(48,162,77),0 0 20px rgb(48,162,77)}.clickable-area .alert-gradient.alert-warning{color:#856404;border-color:#8564044d;background:linear-gradient(105deg,#fff0c0,#fffbed 68%,#fff);box-shadow:0 5px 12px #0000001a,0 14px 30px #8564041a}.clickable-area .alert-gradient.alert-warning .alert-icon{color:#856404;background-color:#ffe599}.clickable-area .alert-gradient.alert-warning .btn-dismiss{color:#856404}.clickable-area .alert-gradient.alert-warning .btn-dismiss:hover{text-shadow:0 0 10px rgb(179,134,0),0 0 20px rgb(179,134,0)}.clickable-area .alert-gradient.alert-error{color:#721c24;border-color:#721c244d;background:linear-gradient(105deg,#fadcdf,#fff7f8 68%,#fff);box-shadow:0 5px 12px #0000001a,0 14px 30px #721c241a}.clickable-area .alert-gradient.alert-error .alert-icon{color:#721c24;background-color:#f7ccd1}.clickable-area .alert-gradient.alert-error .btn-dismiss{color:#721c24}.clickable-area .alert-gradient.alert-error .btn-dismiss:hover{text-shadow:0 0 10px rgb(255,76,89),0 0 20px rgb(255,76,89)}@media(prefers-reduced-motion:reduce){.clickable-area,.clickable-area *{transition-duration:1ms!important;animation-duration:1ms!important}}@keyframes alert-content-in{0%{opacity:0}to{opacity:1}}@keyframes alert-content-out{to{opacity:0}}@keyframes alert-enter-dot{0%{transform:scale(0);opacity:0;border-width:0}to{transform:none;opacity:1;border-width:1px}}@keyframes alert-enter-burst{0%{transform:scale(.72);opacity:0;border-width:0}to{transform:scale(1);opacity:1;border-width:1px}}@keyframes alert-enter-drop{0%{transform:translateY(-48px) scale(.98);opacity:0;border-width:0}64%{transform:translateY(5px) scale(1.01);opacity:1;border-width:1px}82%{transform:translateY(-2px) scale(.995)}to{transform:translateY(0) scale(1);opacity:1;border-width:1px}}@keyframes alert-enter-slide-right{0%{transform:translate(42px);opacity:0;border-width:0}to{transform:translate(0);opacity:1;border-width:1px}}@keyframes alert-enter-slide-left{0%{transform:translate(-42px);opacity:0;border-width:0}to{transform:translate(0);opacity:1;border-width:1px}}@keyframes alert-enter-unfold{0%{transform:scaleY(.02);opacity:0;border-width:0}to{transform:scaleY(1);opacity:1;border-width:1px}}@keyframes alert-leave-dot{to{transform:scale(0);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-burst{to{transform:scale(.82);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-drop{to{transform:translateY(18px) scale(.98);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-slide-right{to{transform:translate(28px);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-slide-left{to{transform:translate(-28px);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-unfold{to{transform:scaleY(.04);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}\n"], dependencies: [{ kind: "pipe", type: NewlineAndTabsPipe, name: "newlineAndTabs" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AlertComponent, decorators: [{
type: Component,
args: [{ selector: 'app-alert', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NewlineAndTabsPipe], template: "@if (alertParams(); as params) {\n <div class=\"clickable-area\">\n @if (isRendered()) {\n <div\n #container\n class=\"alert-container alert-{{ params.type }} alert-{{ fixedAlertAppearance() }} {{ animationClass() }}\"\n role=\"alert\"\n (animationend)=\"onContainerAnimationEnd($event)\">\n\n <div class=\"alert-icon\" aria-hidden=\"true\">\n @switch (params.type) {\n @case ('info') {\n <i class=\"fa fa-info-circle\"></i>\n }\n @case ('success') {\n <i class=\"fa fa-check\"></i>\n }\n @case ('warning') {\n <i class=\"fa fa-exclamation-triangle\"></i>\n }\n @case ('error') {\n <i class=\"fa fa-exclamation-triangle\"></i>\n }\n }\n </div>\n\n <div class=\"alert-text\" [innerHtml]=\"params.text | newlineAndTabs\"></div>\n\n <button type=\"button\" class=\"btn-dismiss\" aria-label=\"Alert schliessen\">\n <i class=\"fa fa-times\"></i>\n </button>\n </div>\n }\n </div>\n}\n", styles: ["@charset \"UTF-8\";.clickable-area{cursor:pointer;margin-top:5px}.clickable-area .alert-container{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:15px;align-items:center;height:var(--h, auto);margin:0;padding:5px 15px;overflow:hidden;border:1px solid;border-radius:4px;z-index:1020!important}.clickable-area .alert-container .alert-icon{display:none}.clickable-area .alert-container .alert-text{min-width:0;overflow-wrap:anywhere;word-break:break-word;font:400 16px/20px Roboto}.clickable-area .alert-container .btn-dismiss{justify-self:end;align-self:baseline;padding:0;border:0;background:transparent;cursor:pointer;font-size:15px}.clickable-area .alert-container.alert-gradient{grid-template-columns:auto minmax(0,1fr) auto;column-gap:12px;padding:10px 10px 10px 14px;border-radius:10px}.clickable-area .alert-container.alert-gradient .alert-icon{align-self:start;display:grid;width:32px;height:32px;place-items:center;border-radius:50%;font-size:16px}.clickable-area .alert-container.alert-gradient .alert-text{font:400 16px/21px Roboto}.clickable-area .alert-container.alert-gradient .btn-dismiss{display:grid;width:28px;height:28px;place-items:center;align-self:start;border-radius:50%;transition:color .16s ease,background-color .16s ease,box-shadow .16s ease}.clickable-area .alert-enter-dot{transform-origin:top left;animation:alert-enter-dot .32s ease both}.clickable-area .alert-enter-dot .alert-text,.clickable-area .alert-enter-dot .alert-icon,.clickable-area .alert-enter-dot .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-dot{height:var(--h, auto);transform-origin:top left;animation:alert-leave-dot .48s ease-in forwards}.clickable-area .alert-leave-dot .alert-text,.clickable-area .alert-leave-dot .alert-icon,.clickable-area .alert-leave-dot .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-burst{transform-origin:center;animation:alert-enter-burst .36s cubic-bezier(.18,1.45,.35,1) both}.clickable-area .alert-enter-burst .alert-text,.clickable-area .alert-enter-burst .alert-icon,.clickable-area .alert-enter-burst .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-burst{height:var(--h, auto);transform-origin:center;animation:alert-leave-burst .42s ease-in forwards}.clickable-area .alert-leave-burst .alert-text,.clickable-area .alert-leave-burst .alert-icon,.clickable-area .alert-leave-burst .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-drop{transform-origin:center top;animation:alert-enter-drop .48s cubic-bezier(.2,1.25,.34,1) both}.clickable-area .alert-enter-drop .alert-text,.clickable-area .alert-enter-drop .alert-icon,.clickable-area .alert-enter-drop .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-drop{height:var(--h, auto);transform-origin:center top;animation:alert-leave-drop .4s ease-in forwards}.clickable-area .alert-leave-drop .alert-text,.clickable-area .alert-leave-drop .alert-icon,.clickable-area .alert-leave-drop .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-slide-right{transform-origin:right center;animation:alert-enter-slide-right .4s cubic-bezier(.22,1,.36,1) both}.clickable-area .alert-enter-slide-right .alert-text,.clickable-area .alert-enter-slide-right .alert-icon,.clickable-area .alert-enter-slide-right .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-slide-right{height:var(--h, auto);transform-origin:right center;animation:alert-leave-slide-right .44s ease-in forwards}.clickable-area .alert-leave-slide-right .alert-text,.clickable-area .alert-leave-slide-right .alert-icon,.clickable-area .alert-leave-slide-right .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-slide-left{transform-origin:left center;animation:alert-enter-slide-left .4s cubic-bezier(.22,1,.36,1) both}.clickable-area .alert-enter-slide-left .alert-text,.clickable-area .alert-enter-slide-left .alert-icon,.clickable-area .alert-enter-slide-left .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-slide-left{height:var(--h, auto);transform-origin:left center;animation:alert-leave-slide-left .44s ease-in forwards}.clickable-area .alert-leave-slide-left .alert-text,.clickable-area .alert-leave-slide-left .alert-icon,.clickable-area .alert-leave-slide-left .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-enter-unfold{transform-origin:center top;animation:alert-enter-unfold .42s cubic-bezier(.22,1,.36,1) both}.clickable-area .alert-enter-unfold .alert-text,.clickable-area .alert-enter-unfold .alert-icon,.clickable-area .alert-enter-unfold .btn-dismiss{animation:alert-content-in .12s linear .12s both}.clickable-area .alert-leave-unfold{height:var(--h, auto);transform-origin:center top;animation:alert-leave-unfold .44s ease-in forwards}.clickable-area .alert-leave-unfold .alert-text,.clickable-area .alert-leave-unfold .alert-icon,.clickable-area .alert-leave-unfold .btn-dismiss{animation:alert-content-out .08s linear forwards}.clickable-area .alert-classic.alert-info{color:#004085;border-color:#004085;background-color:#b8daff;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014}.clickable-area .alert-classic.alert-info .btn-dismiss{color:inherit}.clickable-area .alert-classic.alert-info .btn-dismiss:hover{text-shadow:0 0 10px rgb(51,102,255),0 0 20px rgb(51,102,255)}.clickable-area .alert-classic.alert-success{color:#155724;border-color:#155724;background-color:#c3e6cb;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014}.clickable-area .alert-classic.alert-success .btn-dismiss{color:inherit}.clickable-area .alert-classic.alert-success .btn-dismiss:hover{text-shadow:0 0 10px rgb(48,162,77),0 0 20px rgb(48,162,77)}.clickable-area .alert-classic.alert-warning{color:#856404;border-color:#856404;background-color:#ffeeba;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014}.clickable-area .alert-classic.alert-warning .btn-dismiss{color:inherit}.clickable-area .alert-classic.alert-warning .btn-dismiss:hover{text-shadow:0 0 10px rgb(179,134,0),0 0 20px rgb(179,134,0)}.clickable-area .alert-classic.alert-error{color:#721c24;border-color:#721c24;background-color:#f8d7da;box-shadow:0 4px 8px #00000014,0 6px 20px #00000014}.clickable-area .alert-classic.alert-error .btn-dismiss{color:inherit}.clickable-area .alert-classic.alert-error .btn-dismiss:hover{text-shadow:0 0 10px rgb(255,76,89),0 0 20px rgb(255,76,89)}.clickable-area .alert-gradient.alert-info{color:#004085;border-color:#0040854d;background:linear-gradient(105deg,#daebff,#f4f9ff 68%,#fff);box-shadow:0 5px 12px #0000001a,0 14px 30px #0040851a}.clickable-area .alert-gradient.alert-info .alert-icon{color:#004085;background-color:#c9e2ff}.clickable-area .alert-gradient.alert-info .btn-dismiss{color:#004085}.clickable-area .alert-gradient.alert-info .btn-dismiss:hover{text-shadow:0 0 10px rgb(51,102,255),0 0 20px rgb(51,102,255)}.clickable-area .alert-gradient.alert-success{color:#155724;border-color:#1557244d;background:linear-gradient(105deg,#d8f0dd,#f6fcf7 68%,#fff);box-shadow:0 5px 12px #0000001a,0 14px 30px #1557241a}.clickable-area .alert-gradient.alert-success .alert-icon{color:#155724;background-color:#c9e8d1}.clickable-area .alert-gradient.alert-success .btn-dismiss{color:#155724}.clickable-area .alert-gradient.alert-success .btn-dismiss:hover{text-shadow:0 0 10px rgb(48,162,77),0 0 20px rgb(48,162,77)}.clickable-area .alert-gradient.alert-warning{color:#856404;border-color:#8564044d;background:linear-gradient(105deg,#fff0c0,#fffbed 68%,#fff);box-shadow:0 5px 12px #0000001a,0 14px 30px #8564041a}.clickable-area .alert-gradient.alert-warning .alert-icon{color:#856404;background-color:#ffe599}.clickable-area .alert-gradient.alert-warning .btn-dismiss{color:#856404}.clickable-area .alert-gradient.alert-warning .btn-dismiss:hover{text-shadow:0 0 10px rgb(179,134,0),0 0 20px rgb(179,134,0)}.clickable-area .alert-gradient.alert-error{color:#721c24;border-color:#721c244d;background:linear-gradient(105deg,#fadcdf,#fff7f8 68%,#fff);box-shadow:0 5px 12px #0000001a,0 14px 30px #721c241a}.clickable-area .alert-gradient.alert-error .alert-icon{color:#721c24;background-color:#f7ccd1}.clickable-area .alert-gradient.alert-error .btn-dismiss{color:#721c24}.clickable-area .alert-gradient.alert-error .btn-dismiss:hover{text-shadow:0 0 10px rgb(255,76,89),0 0 20px rgb(255,76,89)}@media(prefers-reduced-motion:reduce){.clickable-area,.clickable-area *{transition-duration:1ms!important;animation-duration:1ms!important}}@keyframes alert-content-in{0%{opacity:0}to{opacity:1}}@keyframes alert-content-out{to{opacity:0}}@keyframes alert-enter-dot{0%{transform:scale(0);opacity:0;border-width:0}to{transform:none;opacity:1;border-width:1px}}@keyframes alert-enter-burst{0%{transform:scale(.72);opacity:0;border-width:0}to{transform:scale(1);opacity:1;border-width:1px}}@keyframes alert-enter-drop{0%{transform:translateY(-48px) scale(.98);opacity:0;border-width:0}64%{transform:translateY(5px) scale(1.01);opacity:1;border-width:1px}82%{transform:translateY(-2px) scale(.995)}to{transform:translateY(0) scale(1);opacity:1;border-width:1px}}@keyframes alert-enter-slide-right{0%{transform:translate(42px);opacity:0;border-width:0}to{transform:translate(0);opacity:1;border-width:1px}}@keyframes alert-enter-slide-left{0%{transform:translate(-42px);opacity:0;border-width:0}to{transform:translate(0);opacity:1;border-width:1px}}@keyframes alert-enter-unfold{0%{transform:scaleY(.02);opacity:0;border-width:0}to{transform:scaleY(1);opacity:1;border-width:1px}}@keyframes alert-leave-dot{to{transform:scale(0);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-burst{to{transform:scale(.82);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-drop{to{transform:translateY(18px) scale(.98);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-slide-right{to{transform:translate(28px);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-slide-left{to{transform:translate(-28px);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}@keyframes alert-leave-unfold{to{transform:scaleY(.04);opacity:0;height:0;padding-top:0;padding-bottom:0;border-width:0;margin-top:-5px}}\n"] }]
}], propDecorators: { alertParams: [{ type: i0.Input, args: [{ isSignal: true, alias: "alertParams", required: true }] }], entryAnimation: [{ type: i0.Input, args: [{ isSignal: true, alias: "entryAnimation", required: true }] }], alertAppearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "alertAppearance", required: true }] }], container: [{ type: i0.ViewChild, args: ['container', { isSignal: true }] }] } });
class AlertsContainerComponent {
constructor() {
this.entryAnimation = input(AlertEntryAnimation.DOT, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "entryAnimation" }] : /* istanbul ignore next */ []));
this.alertAppearance = input(AlertAppearance.CLASSIC, /* @ts-ignore */
...(ngDevMode ? [{ debugName: "alertAppearance" }] : /* istanbul ignore next */ []));
this.alerts = input([], /* @ts-ignore */
...(ngDevMode ? [{ debugName: "alerts" }] : /* istanbul ignore next */ []));
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AlertsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: AlertsContainerComponent, isStandalone: true, selector: "magic-alerts", inputs: { entryAnimation: { classPropertyName: "entryAnimation", publicName: "entryAnimation", isSignal: true, isRequired: false, transformFunction: null }, alertAppearance: { classPropertyName: "alertAppearance", publicName: "alertAppearance", isSignal: true, isRequired: false, transformFunction: null }, alerts: { classPropertyName: "alerts", publicName: "alerts", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<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(); track alertParams.id) {\n\t\t<app-alert\n\t\t\t[alertParams]=\"alertParams\"\n\t\t\t[entryAnimation]=\"entryAnimation()\"\n\t\t\t[alertAppearance]=\"alertAppearance()\">\n\t\t</app-alert>\n\t}\n</div>\n", 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", "entryAnimation", "alertAppearance"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AlertsContainerComponent, decorators: [{
type: Component,
args: [{ selector: 'magic-alerts', changeDetection: ChangeDetectionStrategy.OnPush, imports: [AlertComponent], template: "<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(); track alertParams.id) {\n\t\t<app-alert\n\t\t\t[alertParams]=\"alertParams\"\n\t\t\t[entryAnimation]=\"entryAnimation()\"\n\t\t\t[alertAppearance]=\"alertAppearance()\">\n\t\t</app-alert>\n\t}\n</div>\n", 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"] }]
}], propDecorators: { entryAnimation: [{ type: i0.Input, args: [{ isSignal: true, alias: "entryAnimation", required: false }] }], alertAppearance: [{ type: i0.Input, args: [{ isSignal: true, alias: "alertAppearance", required: false }] }], alerts: [{ type: i0.Input, args: [{ isSignal: true, alias: "alerts", required: false }] }] } });
const DEFAULT_MAGIC_ALERTS_CONFIG = {
entryAnimation: AlertEntryAnimation.DOT,
alertAppearance: AlertAppearance.CLASSIC
};
const MAGIC_ALERTS_CONFIG = new InjectionToken('MAGIC_ALERTS_CONFIG', {
providedIn: 'root',
factory: () => DEFAULT_MAGIC_ALERTS_CONFIG
});
function provideMagicAlerts(config = {}) {
return makeEnvironmentProviders([
{
provide: MAGIC_ALERTS_CONFIG,
useValue: {
...DEFAULT_MAGIC_ALERTS_CONFIG,
...config
}
}
]);
}
class AlertsService {
constructor() {
this.alertsStore = inject(AlertsStore);
this.applicationRef = inject(ApplicationRef);
this.injector = inject(Injector);
this.config = inject(MAGIC_ALERTS_CONFIG);
this.renderQueued = false;
this.initializeAlertsComponent();
}
initializeAlertsComponent() {
// Create a div element and append it to the document body
const hostElement = document.createElement('div');
document.body.appendChild(hostElement);
// Create AlertsContainerComponent and attach it to the DOM
this.alertsComponentRef = createComponent(AlertsContainerComponent, {
hostElement,
environmentInjector: this.applicationRef.injector,
elementInjector: this.injector
});
this.alertsComponentRef.setInput('entryAnimation', this.config.entryAnimation);
this.alertsComponentRef.setInput('alertAppearance', this.config.alertAppearance);
this.alertsComponentRef.setInput('alerts', this.alertsStore.alerts());
// Attach the AlertsContainerComponent to the application
this.applicationRef.attachView(this.alertsComponentRef.hostView);
this.alertsComponentRef.changeDetectorRef.detectChanges();
}
showInfo(text, dismissTimeInMillis = 10_000) {
this.alertsStore.addAlert(text, 'info', dismissTimeInMillis);
this.syncAlertsToContainer();
this.queueContainerRender();
}
showSuccess(text, dismissTimeInMillis = 4_000) {
this.alertsStore.addAlert(text, 'success', dismissTimeInMillis);
this.syncAlertsToContainer();
this.queueContainerRender();
}
showWarning(text, dismissTimeInMillis = 10_000) {
this.alertsStore.addAlert(text, 'warning', dismissTimeInMillis);
this.syncAlertsToContainer();
this.queueContainerRender();
}
showError(text, dismissTimeInMillis = 2_147_483_647) {
this.alertsStore.addAlert(text, 'error', dismissTimeInMillis);
this.syncAlertsToContainer();
this.queueContainerRender();
}
setEntryAnimation(entryAnimation) {
this.alertsComponentRef.setInput('entryAnimation', entryAnimation);
this.queueContainerRender();
}
setAlertAppearance(alertAppearance) {
this.alertsComponentRef.setInput('alertAppearance', alertAppearance);
this.queueContainerRender();
}
clear() {
this.alertsStore.dismissAll();
this.queueContainerRender();
}
syncAlertsToContainer() {
this.alertsComponentRef.setInput('alerts', this.alertsStore.alerts());
}
queueContainerRender() {
// This container is created outside the normal component tree, so input updates
// need an explicit render pass to show reliably in production and zoneless apps.
if (this.renderQueued) {
return;
}
this.renderQueued = true;
queueMicrotask(() => {
this.renderQueued = false;
this.alertsComponentRef.changeDetectorRef.detectChanges();
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AlertsService, deps: [], target: i0.ɵɵFactoryTarget.Service }); }
static { this.ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.0", ngImport: i0, type: AlertsService }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: AlertsService, decorators: [{
type: Service
}], ctorParameters: () => [] });
class MockAlertsService {
showInfo(text, dismissTimeInMillis = 10_000) { }
showSuccess(text, dismissTimeInMillis = 4_000) { }
showWarning(text, dismissTimeInMillis = 10_000) { }
showError(text, dismissTimeInMillis = 2_147_483_647) { }
setEntryAnimation(entryAnimation) { }
setAlertAppearance(alertAppearance) { }
clear() { }
}
/*
* Public API Surface of mk-magic-alerts
*/
/**
* Generated bundle index. Do not edit.
*/
export { AlertAppearance, AlertEntryAnimation, AlertsService, DEFAULT_MAGIC_ALERTS_CONFIG, MAGIC_ALERTS_CONFIG, MockAlertsService, provideMagicAlerts };
//# sourceMappingURL=mk-magic-alerts.mjs.map