@gokula-krishnan/notify-lib
Version:
🔥 Angular toast notification library with position, hover pause, and close support.
185 lines (177 loc) • 11.3 kB
JavaScript
import * as i0 from '@angular/core';
import { Component, EventEmitter, Output, Input, Injectable } from '@angular/core';
import * as i1 from '@angular/common';
import { CommonModule } from '@angular/common';
import { trigger, transition, style, animate } from '@angular/animations';
import { BehaviorSubject } from 'rxjs';
class NotifyLib {
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: NotifyLib, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: NotifyLib, isStandalone: true, selector: "lib-notify-lib", ngImport: i0, template: `
<p>
notify-lib works!
</p>
`, isInline: true, styles: [""] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: NotifyLib, decorators: [{
type: Component,
args: [{ selector: 'lib-notify-lib', imports: [], template: `
<p>
notify-lib works!
</p>
` }]
}] });
class ToastComponent {
toast;
pauseTimer = new EventEmitter();
close = new EventEmitter();
pause() {
this.pauseTimer.emit(true);
}
resume() {
this.pauseTimer.emit(false);
}
get icon() {
switch (this.toast.type) {
case 'success': return '✔️';
case 'error': return '❌';
case 'info': return 'ℹ️';
case 'warning': return '⚠️';
default: return '';
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: ToastComponent, isStandalone: true, selector: "lib-toast", inputs: { toast: "toast" }, outputs: { pauseTimer: "pauseTimer", close: "close" }, ngImport: i0, template: "<div class=\"toast\" [@fade] [ngClass]=\"toast.type\" *ngIf=\"toast?.message\" (mouseenter)=\"pause()\" (mouseleave)=\"resume()\">\r\n <span class=\"icon\">{{ icon }}</span>\r\n <span class=\"message\">{{ toast.message }}</span>\r\n <button class=\"close\" (click)=\"close.emit()\">\u2716</button>\r\n</div>", styles: [".toast{padding:.75rem 1rem;border-radius:6px;margin-bottom:.5rem;color:#fff;cursor:pointer;font-weight:700;box-shadow:0 2px 8px #0003;transition:transform .3s ease}.success{background-color:#28a745}.error{background-color:#dc3545}.info{background-color:#17a2b8}.warning{background-color:#ffc107;color:#000}.toast{position:relative;display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;border-radius:6px;margin-bottom:.5rem;color:#fff;font-weight:700;box-shadow:0 2px 8px #0003;transition:opacity .3s ease}.toast .close{background:none;border:none;color:inherit;font-size:1rem;cursor:pointer;margin-left:1rem}.toast{display:flex;align-items:center}.toast .icon{margin-right:.5rem}.toast .message{flex:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [
trigger('fade', [
transition(':enter', [
style({ opacity: 0, transform: 'translateY(-10px)' }),
animate('300ms ease-out', style({ opacity: 1, transform: 'translateY(0)' })),
]),
transition(':leave', [
animate('300ms ease-in', style({ opacity: 0, transform: 'translateY(-10px)' })),
]),
]),
] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ToastComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-toast', standalone: true, imports: [CommonModule], animations: [
trigger('fade', [
transition(':enter', [
style({ opacity: 0, transform: 'translateY(-10px)' }),
animate('300ms ease-out', style({ opacity: 1, transform: 'translateY(0)' })),
]),
transition(':leave', [
animate('300ms ease-in', style({ opacity: 0, transform: 'translateY(-10px)' })),
]),
]),
], template: "<div class=\"toast\" [@fade] [ngClass]=\"toast.type\" *ngIf=\"toast?.message\" (mouseenter)=\"pause()\" (mouseleave)=\"resume()\">\r\n <span class=\"icon\">{{ icon }}</span>\r\n <span class=\"message\">{{ toast.message }}</span>\r\n <button class=\"close\" (click)=\"close.emit()\">\u2716</button>\r\n</div>", styles: [".toast{padding:.75rem 1rem;border-radius:6px;margin-bottom:.5rem;color:#fff;cursor:pointer;font-weight:700;box-shadow:0 2px 8px #0003;transition:transform .3s ease}.success{background-color:#28a745}.error{background-color:#dc3545}.info{background-color:#17a2b8}.warning{background-color:#ffc107;color:#000}.toast{position:relative;display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;border-radius:6px;margin-bottom:.5rem;color:#fff;font-weight:700;box-shadow:0 2px 8px #0003;transition:opacity .3s ease}.toast .close{background:none;border:none;color:inherit;font-size:1rem;cursor:pointer;margin-left:1rem}.toast{display:flex;align-items:center}.toast .icon{margin-right:.5rem}.toast .message{flex:1}\n"] }]
}], propDecorators: { toast: [{
type: Input
}], pauseTimer: [{
type: Output
}], close: [{
type: Output
}] } });
class NotificationService {
toasts = [];
toastSubject = new BehaviorSubject([]);
toastStream$ = this.toastSubject.asObservable();
// ✅ Store timeout handles to support pause/resume
toastTimeouts = new Map();
generateId() {
return Date.now().toString();
}
show(message, type = 'info', duration = 3000) {
const id = crypto.randomUUID(); // Unique ID
const toast = { id, message, type, duration };
this.toasts.push(toast);
this.toastSubject.next([...this.toasts]);
const timeout = setTimeout(() => {
this.remove(id);
}, duration);
this.toastTimeouts.set(id, timeout);
}
remove(id) {
this.toasts = this.toasts.filter(t => t.id !== id);
this.toastSubject.next([...this.toasts]);
if (this.toastTimeouts.has(id)) {
clearTimeout(this.toastTimeouts.get(id));
this.toastTimeouts.delete(id);
}
}
pause(id) {
if (this.toastTimeouts.has(id)) {
clearTimeout(this.toastTimeouts.get(id));
this.toastTimeouts.delete(id); // Optional cleanup
}
}
resume(id, duration = 3000) {
const timeout = setTimeout(() => {
this.remove(id);
}, duration);
this.toastTimeouts.set(id, timeout);
}
// Helper methods
success(msg) {
this.show(msg, 'success');
}
error(msg) {
this.show(msg, 'error');
}
info(msg) {
this.show(msg, 'info');
}
warning(msg) {
this.show(msg, 'warning');
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: NotificationService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: NotificationService, decorators: [{
type: Injectable,
args: [{ providedIn: 'root' }]
}] });
class ToastContainerComponent {
notifyService;
toasts = [];
position = 'top-right';
constructor(notifyService) {
this.notifyService = notifyService;
}
ngOnInit() {
this.notifyService.toastStream$.subscribe(toasts => {
this.toasts = toasts;
});
}
pausedToasts = new Set();
pause(id, isPaused) {
if (isPaused)
this.pausedToasts.add(id);
else
this.pausedToasts.delete(id);
}
dismiss(id) {
if (!this.pausedToasts.has(id)) {
this.notifyService.remove(id);
}
}
trackById(index, toast) {
return toast.id;
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ToastContainerComponent, deps: [{ token: NotificationService }], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.0.6", type: ToastContainerComponent, isStandalone: true, selector: "lib-toast-container", inputs: { position: "position" }, ngImport: i0, template: "<div [ngClass]=\"['toast-container', position]\">\r\n <lib-toast\r\n *ngFor=\"let toast of toasts; trackBy: trackById\"\r\n [toast]=\"toast\"\r\n (pauseTimer)=\"pause(toast.id, $event)\"\r\n (close)=\"dismiss(toast.id)\">\r\n </lib-toast>\r\n</div>\r\n", styles: [".toast-container{position:fixed;z-index:1000;display:flex;flex-direction:column;gap:.5rem}.toast-container.top-right{top:1rem;right:1rem}.toast-container.top-left{top:1rem;left:1rem}.toast-container.bottom-right{bottom:1rem;right:1rem}.toast-container.bottom-left{bottom:1rem;left:1rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ToastComponent, selector: "lib-toast", inputs: ["toast"], outputs: ["pauseTimer", "close"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.0.6", ngImport: i0, type: ToastContainerComponent, decorators: [{
type: Component,
args: [{ selector: 'lib-toast-container', standalone: true, imports: [CommonModule, ToastComponent], template: "<div [ngClass]=\"['toast-container', position]\">\r\n <lib-toast\r\n *ngFor=\"let toast of toasts; trackBy: trackById\"\r\n [toast]=\"toast\"\r\n (pauseTimer)=\"pause(toast.id, $event)\"\r\n (close)=\"dismiss(toast.id)\">\r\n </lib-toast>\r\n</div>\r\n", styles: [".toast-container{position:fixed;z-index:1000;display:flex;flex-direction:column;gap:.5rem}.toast-container.top-right{top:1rem;right:1rem}.toast-container.top-left{top:1rem;left:1rem}.toast-container.bottom-right{bottom:1rem;right:1rem}.toast-container.bottom-left{bottom:1rem;left:1rem}\n"] }]
}], ctorParameters: () => [{ type: NotificationService }], propDecorators: { position: [{
type: Input
}] } });
/*
* Public API Surface of notify-lib
*/
/**
* Generated bundle index. Do not edit.
*/
export { NotificationService, NotifyLib, ToastContainerComponent };
//# sourceMappingURL=notify-lib.mjs.map