UNPKG

@gokula-krishnan/notify-lib

Version:

🔥 Angular toast notification library with position, hover pause, and close support.

185 lines (177 loc) 11.3 kB
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