@sixbell-telco/sdk
Version:
A collection of reusable components designed for use in Sixbell Telco Angular projects
172 lines (166 loc) • 12.8 kB
JavaScript
import * as i0 from '@angular/core';
import { signal, computed, Injectable, input, output, Component, inject } from '@angular/core';
import { generateUniqueId } from '@sixbell-telco/sdk/utils/generators/uuid';
import { NgClass } from '@angular/common';
import { IconComponent } from '@sixbell-telco/sdk/components/icon';
import { matCheckCircleOutline, matWarningOutline, matErrorOutline, matInfoOutline } from '@sixbell-telco/sdk/components/icon/material/outline';
import { TypographyDirective } from '@sixbell-telco/sdk/directives/typography';
import { cn } from '@sixbell-telco/sdk/utils/cn';
import { cva } from 'class-variance-authority';
var ToastTypes;
(function (ToastTypes) {
ToastTypes["SUCCESS"] = "toast-success";
ToastTypes["ERROR"] = "toast-error";
ToastTypes["INFO"] = "toast-info";
ToastTypes["WARNING"] = "toast-warning";
})(ToastTypes || (ToastTypes = {}));
class ToastService {
toastsSignal = signal([]);
expandedSignal = signal(false);
// Create computed signals for derived state
toasts = computed(() => this.toastsSignal());
expanded = computed(() => this.expandedSignal());
isEmpty = computed(() => this.toasts().length === 0);
notify(type, message, title = '', duration = 10000) {
const toast = {
id: generateUniqueId(),
type,
message,
title,
duration,
animate: 'enter',
};
// Create a new array reference to ensure change detection
this.toastsSignal.update((toasts) => [toast, ...toasts]);
this.scheduleDismiss(toast);
}
scheduleDismiss(toast) {
setTimeout(() => {
this.remove(toast);
}, toast.duration);
}
animateRemoval(toast) {
this.toastsSignal.update((toasts) => toasts.map((t) => (t.id === toast.id ? { ...t, animate: 'leave' } : t)));
}
remove(toast) {
this.toastsSignal.update((toasts) => toasts.filter((t) => t.id !== toast.id));
if (this.isEmpty()) {
this.collapse();
}
}
clear() {
this.toastsSignal.set([]);
this.collapse();
}
toggle() {
this.expandedSignal.update((expanded) => !expanded);
}
collapse() {
this.expandedSignal.set(false);
}
expand() {
this.expandedSignal.set(true);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: ToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: ToastService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: ToastService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}] });
const toastComponent = cva([
'toast-message relative mb-2 flex min-h-20 h-20 w-[400px] cursor-pointer items-center rounded-lg border-2 bg-base-200 p-2 transition-all duration-300 ease-ease-in-and-out-back',
], {
variants: {
variant: {
info: ['border-primary', 'text-primary'],
success: ['border-success', 'text-success'],
warning: ['border-warning', 'text-warning'],
error: ['border-error', 'text-error'],
},
},
compoundVariants: [],
defaultVariants: {
variant: 'info',
},
});
class ToastMessageComponent {
variant = input();
classes = input('');
types = ToastTypes;
toast = input.required();
toastAmount = input.required();
toastIndex = input.required();
clicked = output();
iconCheckCircle = matCheckCircleOutline;
iconWarning = matWarningOutline;
iconError = matErrorOutline;
iconInfo = matInfoOutline;
componentClass = computed(() => {
const toast = this.toast();
const classes = this.classes();
switch (toast.type) {
case this.types.SUCCESS:
return cn(toastComponent({ variant: 'success', class: classes }));
case this.types.ERROR:
return cn(toastComponent({ variant: 'error', class: classes }));
case this.types.WARNING:
return cn(toastComponent({ variant: 'warning', class: classes }));
case this.types.INFO:
return cn(toastComponent({ variant: 'info', class: classes }));
default:
return cn(toastComponent({ variant: 'info', class: classes }));
}
});
handleClose() {
this.clicked.emit(this.toast());
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: ToastMessageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.0", type: ToastMessageComponent, isStandalone: true, selector: "st-toast-message", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, classes: { classPropertyName: "classes", publicName: "classes", isSignal: true, isRequired: false, transformFunction: null }, toast: { classPropertyName: "toast", publicName: "toast", isSignal: true, isRequired: true, transformFunction: null }, toastAmount: { classPropertyName: "toastAmount", publicName: "toastAmount", isSignal: true, isRequired: true, transformFunction: null }, toastIndex: { classPropertyName: "toastIndex", publicName: "toastIndex", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { clicked: "clicked" }, ngImport: i0, template: "<!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->\n<li\n\t[class]=\"componentClass()\"\n\t[ngClass]=\"{\n\t\t'animate-toast-slide-out bottom-0': toast().animate === 'leave' && toastAmount() > 1,\n\t\t'animate-slide-out': toast().animate === 'leave' && toastAmount() === 1,\n\t\t'animate-fade-out': toast().animate === 'leave' && toastAmount() > 1 && toastIndex() === 0,\n\t\t'animate-slide-in': toast().animate === 'enter',\n\t}\"\n\t(click)=\"handleClose()\"\n\trole=\"button\"\n\ttabindex=\"0\"\n>\n\t<div class=\"flex flex-1 items-center justify-center\">\n\t\t@if (this.toast().type === this.types.SUCCESS) {\n\t\t\t<st-icon [icon]=\"iconCheckCircle\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t} @else if (this.toast().type === this.types.WARNING) {\n\t\t\t<st-icon [icon]=\"iconWarning\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t} @else if (this.toast().type === this.types.ERROR) {\n\t\t\t<st-icon [icon]=\"iconError\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t} @else if (this.toast().type === this.types.INFO) {\n\t\t\t<st-icon [icon]=\"iconInfo\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t}\n\t</div>\n\t<div class=\"flex-4\">\n\t\t<div class=\"grid grid-rows-[min-content_1fr]\">\n\t\t\t<div typography [tyVariant]=\"'body-sm'\" [tyColor]=\"'base'\" [tyFontWeight]=\"'semibold'\">{{ toast().title }}</div>\n\t\t\t<div typography [tyVariant]=\"'body-xs'\" [tyColor]=\"'base'\" [tyFontWeight]=\"'normal'\">\n\t\t\t\t{{ toast().message }}\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</li>\n", dependencies: [{ kind: "directive", type: TypographyDirective, selector: "[typography]", inputs: ["tyVariant", "tyColor", "tyFontWeight", "tyTextOverflow"] }, { kind: "component", type: IconComponent, selector: "st-icon", inputs: ["color", "size", "icon"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: ToastMessageComponent, decorators: [{
type: Component,
args: [{ selector: 'st-toast-message', imports: [TypographyDirective, IconComponent, NgClass], template: "<!-- eslint-disable @angular-eslint/template/click-events-have-key-events -->\n<li\n\t[class]=\"componentClass()\"\n\t[ngClass]=\"{\n\t\t'animate-toast-slide-out bottom-0': toast().animate === 'leave' && toastAmount() > 1,\n\t\t'animate-slide-out': toast().animate === 'leave' && toastAmount() === 1,\n\t\t'animate-fade-out': toast().animate === 'leave' && toastAmount() > 1 && toastIndex() === 0,\n\t\t'animate-slide-in': toast().animate === 'enter',\n\t}\"\n\t(click)=\"handleClose()\"\n\trole=\"button\"\n\ttabindex=\"0\"\n>\n\t<div class=\"flex flex-1 items-center justify-center\">\n\t\t@if (this.toast().type === this.types.SUCCESS) {\n\t\t\t<st-icon [icon]=\"iconCheckCircle\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t} @else if (this.toast().type === this.types.WARNING) {\n\t\t\t<st-icon [icon]=\"iconWarning\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t} @else if (this.toast().type === this.types.ERROR) {\n\t\t\t<st-icon [icon]=\"iconError\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t} @else if (this.toast().type === this.types.INFO) {\n\t\t\t<st-icon [icon]=\"iconInfo\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t}\n\t</div>\n\t<div class=\"flex-4\">\n\t\t<div class=\"grid grid-rows-[min-content_1fr]\">\n\t\t\t<div typography [tyVariant]=\"'body-sm'\" [tyColor]=\"'base'\" [tyFontWeight]=\"'semibold'\">{{ toast().title }}</div>\n\t\t\t<div typography [tyVariant]=\"'body-xs'\" [tyColor]=\"'base'\" [tyFontWeight]=\"'normal'\">\n\t\t\t\t{{ toast().message }}\n\t\t\t</div>\n\t\t</div>\n\t</div>\n</li>\n" }]
}] });
class ToastsContainerComponent {
toastService = inject(ToastService);
containerClasses = computed(() => {
const toastCount = this.toastService.toasts().length;
const isExpanded = this.toastService.expanded();
return {
'min-h-64': toastCount === 3 && isExpanded,
'min-h-48': toastCount === 2 && isExpanded,
'h-24 min-h-24': toastCount === 1 && isExpanded,
'h-28 min-h-28': toastCount > 0 && !isExpanded,
'h-0 min-h-0': toastCount === 0 && !isExpanded,
};
});
handleExpand() {
this.toastService.expand();
}
handleCollapse() {
this.toastService.collapse();
}
handleRemove(toast) {
this.toastService.animateRemoval(toast);
setTimeout(() => {
this.toastService.remove(toast);
}, 500);
}
getToastIndex(toast) {
return this.toastService.toasts().findIndex((t) => t.id === toast.id);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: ToastsContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.0", type: ToastsContainerComponent, isStandalone: true, selector: "st-toasts-container", ngImport: i0, template: "<section class=\"fixed bottom-2 right-4 z-10\">\n\t<ol\n\t\tclass=\"toast-container group flex min-w-[400px] flex-col gap-2\"\n\t\t[ngClass]=\"containerClasses()\"\n\t\t[attr.aria-expanded]=\"toastService.expanded()\"\n\t\t(mouseenter)=\"handleExpand()\"\n\t\t(mouseleave)=\"handleCollapse()\"\n\t>\n\t\t@for (toast of toastService.toasts(); track toast.id) {\n\t\t\t<st-toast-message\n\t\t\t\t[toast]=\"toast\"\n\t\t\t\t[toastIndex]=\"getToastIndex(toast)\"\n\t\t\t\t[toastAmount]=\"toastService.toasts().length\"\n\t\t\t\t(clicked)=\"handleRemove($event)\"\n\t\t\t/>\n\t\t}\n\t</ol>\n</section>\n", dependencies: [{ kind: "component", type: ToastMessageComponent, selector: "st-toast-message", inputs: ["variant", "classes", "toast", "toastAmount", "toastIndex"], outputs: ["clicked"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: ToastsContainerComponent, decorators: [{
type: Component,
args: [{ selector: 'st-toasts-container', imports: [ToastMessageComponent, NgClass], template: "<section class=\"fixed bottom-2 right-4 z-10\">\n\t<ol\n\t\tclass=\"toast-container group flex min-w-[400px] flex-col gap-2\"\n\t\t[ngClass]=\"containerClasses()\"\n\t\t[attr.aria-expanded]=\"toastService.expanded()\"\n\t\t(mouseenter)=\"handleExpand()\"\n\t\t(mouseleave)=\"handleCollapse()\"\n\t>\n\t\t@for (toast of toastService.toasts(); track toast.id) {\n\t\t\t<st-toast-message\n\t\t\t\t[toast]=\"toast\"\n\t\t\t\t[toastIndex]=\"getToastIndex(toast)\"\n\t\t\t\t[toastAmount]=\"toastService.toasts().length\"\n\t\t\t\t(clicked)=\"handleRemove($event)\"\n\t\t\t/>\n\t\t}\n\t</ol>\n</section>\n" }]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { ToastMessageComponent, ToastService, ToastTypes, ToastsContainerComponent, toastComponent };
//# sourceMappingURL=sixbell-telco-sdk-components-toast.mjs.map