ngx-toasta
Version:
Simple and clean Angular Toast component that shows growl-style notifications and messages for your web app
523 lines (513 loc) • 21.8 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, Pipe, EventEmitter, Component, Input, Output, NgModule } from '@angular/core';
import { Subject } from 'rxjs';
import * as i1$1 from '@angular/common';
import { CommonModule } from '@angular/common';
import * as i1 from '@angular/platform-browser';
/**
* Check and return true if an object is type of string
* @param obj Analyse has to object the string type
* @return result of analysis
*/
function isString(obj) {
return typeof obj === 'string';
}
/**
* Check and return true if an object is type of number
* @param obj Analyse has to object the boolean type
* @return result of analysis
*/
function isNumber(obj) {
return typeof obj === 'number';
}
/**
* Check and return true if an object is type of Function
* @param obj Analyse has to object the function type
* @return result of analysis
*/
function isFunction(obj) {
return typeof obj === 'function';
}
/**
* Options to configure a new Toast
*/
class ToastOptions {
}
ToastOptions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastOptions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
ToastOptions.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastOptions });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastOptions, decorators: [{
type: Injectable
}] });
/**
* Structrure of a created Toast
*/
class ToastData {
}
ToastData.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastData, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
ToastData.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastData });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastData, decorators: [{
type: Injectable
}] });
/**
* Default configuration for all toasts and toasta container
*/
class ToastaConfig {
constructor() {
// Maximum number of toasties to show at once
this.limit = 5;
// Whether to show the 'X' icon to close the toast
this.showClose = true;
// Whether to show a progress bar at the bottom of the notification
this.showDuration = true;
// The window position where the toast pops up
this.position = 'bottom-right';
// How long (in miliseconds) the toasta shows before it's removed. Set to null/0 to turn off.
this.timeout = 5000;
// What theme to use
this.theme = 'default';
}
}
ToastaConfig.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
ToastaConfig.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaConfig });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaConfig, decorators: [{
type: Injectable
}] });
var ToastaEventType;
(function (ToastaEventType) {
ToastaEventType[ToastaEventType["ADD"] = 0] = "ADD";
ToastaEventType[ToastaEventType["CLEAR"] = 1] = "CLEAR";
ToastaEventType[ToastaEventType["CLEAR_ALL"] = 2] = "CLEAR_ALL";
})(ToastaEventType || (ToastaEventType = {}));
class ToastaEvent {
constructor(type, value) {
this.type = type;
this.value = value;
}
}
function toastaServiceFactory(config) {
return new ToastaService(config);
}
/**
* Toasta service helps create different kinds of Toasts
*/
class ToastaService {
constructor(config) {
this.config = config;
// Init the counter
this.uniqueCounter = 0;
// ToastData event emitter
// private toastsEmitter: EventEmitter<ToastData> = new EventEmitter<ToastData>();
// Clear event emitter
// private clearEmitter: EventEmitter<number> = new EventEmitter<number>();
this.eventSource = new Subject();
this.events = this.eventSource.asObservable();
}
/**
* Get list of toats
*/
// getToasts(): Observable<ToastData> {
// return this.toastsEmitter.asObservable();
// }
// getClear(): Observable<number> {
// return this.clearEmitter.asObservable();
// }
/**
* Create Toast of a default type
*/
default(options) {
this.add(options, 'default');
}
/**
* Create Toast of info type
* @param options Individual toasta config overrides
*/
info(options) {
this.add(options, 'info');
}
/**
* Create Toast of success type
* @param options Individual toasta config overrides
*/
success(options) {
this.add(options, 'success');
}
/**
* Create Toast of wait type
* @param options Individual toasta config overrides
*/
wait(options) {
this.add(options, 'wait');
}
/**
* Create Toast of error type
* @param options Individual toasta config overrides
*/
error(options) {
this.add(options, 'error');
}
/**
* Create Toast of warning type
* @param options Individual toasta config overrides
*/
warning(options) {
this.add(options, 'warning');
}
// Add a new toast item
add(options, type) {
var _a;
let toastaOptions;
if (isString(options) && options !== '' || isNumber(options)) {
toastaOptions = {
title: options.toString()
};
}
else {
toastaOptions = options;
}
if (!toastaOptions || !toastaOptions.title && !toastaOptions.msg) {
throw new Error('ngx-toasta: No toast title or message specified!');
}
type = type || 'default';
// Set a unique counter for an id
this.uniqueCounter++;
// Set the local vs global config items
const showClose = this._checkConfigBooleanItem(this.config, toastaOptions, 'showClose');
// Set the local vs global config items
const showDuration = this._checkConfigBooleanItem(this.config, toastaOptions, 'showDuration');
// If we have a theme set, make sure it's a valid one
let theme;
if (toastaOptions.theme) {
theme = ToastaService.THEMES.indexOf(toastaOptions.theme) > -1 ? toastaOptions.theme : this.config.theme;
}
else {
theme = this.config.theme;
}
const toast = {
id: this.uniqueCounter,
title: toastaOptions.title,
msg: toastaOptions.msg,
showClose,
showDuration,
type: 'toasta-type-' + type,
theme: 'toasta-theme-' + theme,
// If there's a timeout individually or globally, set the toast to timeout
// Allows a caller to pass null/0 and override the default. Can also set the default to null/0 to turn off.
timeout: toastaOptions.hasOwnProperty('timeout') ? (_a = toastaOptions.timeout) !== null && _a !== void 0 ? _a : 0 : this.config.timeout,
onAdd: toastaOptions.onAdd && isFunction(toastaOptions.onAdd) ? toastaOptions.onAdd : undefined,
onRemove: toastaOptions.onRemove && isFunction(toastaOptions.onRemove) ? toastaOptions.onRemove : undefined
};
// Push up a new toast item
// this.toastsSubscriber.next(toast);
// this.toastsEmitter.next(toast);
this.emitEvent(new ToastaEvent(ToastaEventType.ADD, toast));
// If we have a onAdd function, call it here
if (toastaOptions.onAdd && isFunction(toastaOptions.onAdd)) {
toastaOptions.onAdd.call(this, toast);
}
}
// Clear all toasts
clearAll() {
// this.clearEmitter.next(null);
this.emitEvent(new ToastaEvent(ToastaEventType.CLEAR_ALL));
}
// Clear the specific one
clear(id) {
// this.clearEmitter.next(id);
this.emitEvent(new ToastaEvent(ToastaEventType.CLEAR, id));
}
// Checks whether the local option is set, if not,
// checks the global config
_checkConfigBooleanItem(config, options, property) {
if (options[property] === false) {
return false;
}
else if (!options[property]) {
return config[property];
}
else {
return true;
}
}
emitEvent(event) {
if (this.eventSource) {
// Push up a new event
this.eventSource.next(event);
}
}
}
// Allowed THEMES
ToastaService.THEMES = ['default', 'material', 'bootstrap'];
ToastaService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaService, deps: [{ token: ToastaConfig }], target: i0.ɵɵFactoryTarget.Injectable });
ToastaService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaService });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaService, decorators: [{
type: Injectable
}], ctorParameters: function () { return [{ type: ToastaConfig }]; } });
class SafeHtmlPipe {
constructor(domSanitized) {
this.domSanitized = domSanitized;
}
transform(value, ...args) {
return this.domSanitized.bypassSecurityTrustHtml(value);
}
}
SafeHtmlPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: SafeHtmlPipe, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe });
SafeHtmlPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: SafeHtmlPipe, name: "safeHtml" });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: SafeHtmlPipe, decorators: [{
type: Pipe,
args: [{ name: 'safeHtml' }]
}], ctorParameters: function () { return [{ type: i1.DomSanitizer }]; } });
/**
* A Toast component shows message with title and close button.
*/
class ToastComponent {
constructor() {
this.progressPercent = 0;
this.startTime = performance.now();
this.closeToastEvent = new EventEmitter();
}
ngAfterViewInit() {
if (this.toast.showDuration && this.toast.timeout > 0) {
this.progressInterval = window.setInterval(() => {
this.progressPercent = (100 - ((performance.now() - this.startTime) / this.toast.timeout * 100)); // Descending progress
if (this.progressPercent <= 0) {
clearInterval(this.progressInterval);
}
}, 16.7); // 60 fps
}
}
/**
* Event handler invokes when user clicks on close button.
* This method emit new event into ToastaContainer to close it.
*/
close($event) {
$event.preventDefault();
this.closeToastEvent.next(this.toast);
if (this.progressInterval) {
clearInterval(this.progressInterval);
}
}
}
ToastComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
ToastComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ToastComponent, selector: "ngx-toast", inputs: { toast: "toast" }, outputs: { closeToastEvent: "closeToast" }, ngImport: i0, template: `
<div class="toast" [ngClass]="[toast.type, toast.theme]">
<div *ngIf="toast.showClose" class="close-button" (click)="close($event)"></div>
<div *ngIf="toast.title || toast.msg" class="toast-text">
<span *ngIf="toast.title" class="toast-title" [innerHTML]="toast.title | safeHtml"></span>
<br *ngIf="toast.title && toast.msg" />
<span *ngIf="toast.msg" class="toast-msg" [innerHtml]="toast.msg | safeHtml"></span>
</div>
<div class="durationbackground" *ngIf="toast.showDuration && toast.timeout > 0">
<div class="durationbar" [style.width.%]="progressPercent">
</div>
</div>
</div>`, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: SafeHtmlPipe, name: "safeHtml" }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastComponent, decorators: [{
type: Component,
args: [{
selector: 'ngx-toast',
template: `
<div class="toast" [ngClass]="[toast.type, toast.theme]">
<div *ngIf="toast.showClose" class="close-button" (click)="close($event)"></div>
<div *ngIf="toast.title || toast.msg" class="toast-text">
<span *ngIf="toast.title" class="toast-title" [innerHTML]="toast.title | safeHtml"></span>
<br *ngIf="toast.title && toast.msg" />
<span *ngIf="toast.msg" class="toast-msg" [innerHtml]="toast.msg | safeHtml"></span>
</div>
<div class="durationbackground" *ngIf="toast.showDuration && toast.timeout > 0">
<div class="durationbar" [style.width.%]="progressPercent">
</div>
</div>
</div>`
}]
}], propDecorators: { toast: [{
type: Input
}], closeToastEvent: [{
type: Output,
args: ['closeToast']
}] } });
/**
* Toasta is container for Toast components
*/
class ToastaComponent {
// The window position where the toast pops up. Possible values:
// - bottom-right (default value from ToastConfig)
// - bottom-left
// - bottom-center
// - bottom-fullwidth
// - top-right
// - top-left
// - top-center
// - top-fullwidth
// - center-center
set position(value) {
if (value) {
let notFound = true;
for (let i = 0; i < ToastaComponent.POSITIONS.length; i++) {
if (ToastaComponent.POSITIONS[i] === value) {
notFound = false;
break;
}
}
if (notFound) {
// Position was wrong - clear it here to use the one from config.
value = this.config.position;
}
}
else {
value = this.config.position;
}
this._position = 'toasta-position-' + value;
}
get position() {
return this._position;
}
constructor(config, toastaService) {
this.config = config;
this.toastaService = toastaService;
this._position = '';
// The storage for toasts.
this.toasts = [];
// Initialise position
this.position = '';
}
/**
* `ngOnInit` is called right after the directive's data-bound properties have been checked for the
* first time, and before any of its children have been checked. It is invoked only once when the
* directive is instantiated.
*/
ngOnInit() {
// We listen events from our service
this.toastaService.events.subscribe((event) => {
if (event.type === ToastaEventType.ADD) {
// Add the new one
const toast = event.value;
this.add(toast);
}
else if (event.type === ToastaEventType.CLEAR) {
// Clear the one by number
const id = event.value;
this.clear(id);
}
else if (event.type === ToastaEventType.CLEAR_ALL) {
// Lets clear all toasts
this.clearAll();
}
});
}
/**
* Event listener of 'closeToast' event comes from ToastaComponent.
* This method removes ToastComponent assosiated with this Toast.
*/
closeToast(toast) {
this.clear(toast.id);
}
/**
* Add new Toast
*/
add(toast) {
// If we've gone over our limit, remove the earliest
// one from the array
if (this.config.limit && this.toasts.length >= this.config.limit) {
this.toasts.shift();
}
// Add toasta to array
this.toasts.push(toast);
//
// If there's a timeout individually or globally,
// set the toast to timeout
if (+toast.timeout) {
this._setTimeout(toast);
}
}
/**
* Clear individual toast by id
* @param id is unique identifier of Toast
*/
clear(id) {
if (id) {
this.toasts.forEach((value, key) => {
if (value.id === id) {
if (value.onRemove && isFunction(value.onRemove)) {
value.onRemove.call(this, value);
}
this.toasts.splice(key, 1);
}
});
}
else {
throw new Error('Please provide id of Toast to close');
}
}
/**
* Clear all toasts
*/
clearAll() {
this.toasts.forEach((value, key) => {
if (value.onRemove && isFunction(value.onRemove)) {
value.onRemove.call(this, value);
}
});
this.toasts = [];
}
/**
* Custom setTimeout function for specific setTimeouts on individual toasts.
*/
_setTimeout(toast) {
window.setTimeout(() => {
this.clear(toast.id);
}, toast.timeout);
}
}
/**
* Set of constants defines position of Toasta on the page.
*/
ToastaComponent.POSITIONS = ['bottom-right', 'bottom-left', 'bottom-center', 'bottom-fullwidth', 'top-right', 'top-left', 'top-center', 'top-fullwidth', 'center-center'];
ToastaComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaComponent, deps: [{ token: ToastaConfig }, { token: ToastaService }], target: i0.ɵɵFactoryTarget.Component });
ToastaComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.2", type: ToastaComponent, selector: "ngx-toasta", inputs: { position: "position" }, ngImport: i0, template: `
<div id="toasta" [ngClass]="[position]">
<ngx-toast *ngFor="let toast of toasts" [toast]="toast" (closeToast)="closeToast(toast)"></ngx-toast>
</div>`, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: ToastComponent, selector: "ngx-toast", inputs: ["toast"], outputs: ["closeToast"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaComponent, decorators: [{
type: Component,
args: [{
selector: 'ngx-toasta',
template: `
<div id="toasta" [ngClass]="[position]">
<ngx-toast *ngFor="let toast of toasts" [toast]="toast" (closeToast)="closeToast(toast)"></ngx-toast>
</div>`
}]
}], ctorParameters: function () { return [{ type: ToastaConfig }, { type: ToastaService }]; }, propDecorators: { position: [{
type: Input
}] } });
let providers = [
ToastaConfig,
{ provide: ToastaService, useFactory: toastaServiceFactory, deps: [ToastaConfig] }
];
class ToastaModule {
static forRoot() {
return {
ngModule: ToastaModule,
providers
};
}
}
ToastaModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
ToastaModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.2", ngImport: i0, type: ToastaModule, declarations: [ToastComponent, ToastaComponent, SafeHtmlPipe], imports: [CommonModule], exports: [ToastComponent, ToastaComponent] });
ToastaModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaModule, providers: providers, imports: [CommonModule] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.2", ngImport: i0, type: ToastaModule, decorators: [{
type: NgModule,
args: [{
imports: [CommonModule],
declarations: [ToastComponent, ToastaComponent, SafeHtmlPipe],
exports: [ToastComponent, ToastaComponent],
providers
}]
}] });
/*
* Public API Surface of ngx-toasta
*/
/**
* Generated bundle index. Do not edit.
*/
export { SafeHtmlPipe, ToastComponent, ToastData, ToastOptions, ToastaComponent, ToastaConfig, ToastaEvent, ToastaEventType, ToastaModule, ToastaService, providers, toastaServiceFactory };
//# sourceMappingURL=ngx-toasta.mjs.map