shirkasoft-ui-components 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/fesm2022/shirkasoft-ui-components-breadcrumb.mjs +199 -0
  2. package/fesm2022/shirkasoft-ui-components-breadcrumb.mjs.map +1 -0
  3. package/fesm2022/shirkasoft-ui-components-button.mjs +148 -0
  4. package/fesm2022/shirkasoft-ui-components-button.mjs.map +1 -0
  5. package/fesm2022/shirkasoft-ui-components-chart.mjs +153 -0
  6. package/fesm2022/shirkasoft-ui-components-chart.mjs.map +1 -0
  7. package/fesm2022/shirkasoft-ui-components-confirm-dialog.mjs +143 -0
  8. package/fesm2022/shirkasoft-ui-components-confirm-dialog.mjs.map +1 -0
  9. package/fesm2022/shirkasoft-ui-components-date-picker.mjs +638 -0
  10. package/fesm2022/shirkasoft-ui-components-date-picker.mjs.map +1 -0
  11. package/fesm2022/shirkasoft-ui-components-fieldset.mjs +94 -0
  12. package/fesm2022/shirkasoft-ui-components-fieldset.mjs.map +1 -0
  13. package/fesm2022/shirkasoft-ui-components-file-upload.mjs +242 -0
  14. package/fesm2022/shirkasoft-ui-components-file-upload.mjs.map +1 -0
  15. package/fesm2022/shirkasoft-ui-components-knob.mjs +269 -0
  16. package/fesm2022/shirkasoft-ui-components-knob.mjs.map +1 -0
  17. package/fesm2022/shirkasoft-ui-components-loading.mjs +255 -0
  18. package/fesm2022/shirkasoft-ui-components-loading.mjs.map +1 -0
  19. package/fesm2022/shirkasoft-ui-components-modal.mjs +290 -0
  20. package/fesm2022/shirkasoft-ui-components-modal.mjs.map +1 -0
  21. package/fesm2022/shirkasoft-ui-components-notification.mjs +143 -0
  22. package/fesm2022/shirkasoft-ui-components-notification.mjs.map +1 -0
  23. package/fesm2022/shirkasoft-ui-components-price-input.mjs +64 -0
  24. package/fesm2022/shirkasoft-ui-components-price-input.mjs.map +1 -0
  25. package/fesm2022/shirkasoft-ui-components-rail-sidebar.mjs +205 -0
  26. package/fesm2022/shirkasoft-ui-components-rail-sidebar.mjs.map +1 -0
  27. package/fesm2022/shirkasoft-ui-components-select.mjs +737 -0
  28. package/fesm2022/shirkasoft-ui-components-select.mjs.map +1 -0
  29. package/fesm2022/shirkasoft-ui-components-sidebar.mjs +185 -0
  30. package/fesm2022/shirkasoft-ui-components-sidebar.mjs.map +1 -0
  31. package/fesm2022/shirkasoft-ui-components-skeleton.mjs +74 -0
  32. package/fesm2022/shirkasoft-ui-components-skeleton.mjs.map +1 -0
  33. package/fesm2022/shirkasoft-ui-components-table.mjs +689 -0
  34. package/fesm2022/shirkasoft-ui-components-table.mjs.map +1 -0
  35. package/fesm2022/shirkasoft-ui-components-tabs.mjs +249 -0
  36. package/fesm2022/shirkasoft-ui-components-tabs.mjs.map +1 -0
  37. package/fesm2022/shirkasoft-ui-components-tag.mjs +70 -0
  38. package/fesm2022/shirkasoft-ui-components-tag.mjs.map +1 -0
  39. package/fesm2022/shirkasoft-ui-components-text-field.mjs +370 -0
  40. package/fesm2022/shirkasoft-ui-components-text-field.mjs.map +1 -0
  41. package/fesm2022/shirkasoft-ui-components-timeline.mjs +222 -0
  42. package/fesm2022/shirkasoft-ui-components-timeline.mjs.map +1 -0
  43. package/fesm2022/shirkasoft-ui-components-toggle.mjs +186 -0
  44. package/fesm2022/shirkasoft-ui-components-toggle.mjs.map +1 -0
  45. package/fesm2022/shirkasoft-ui-components-tooltip.mjs +169 -0
  46. package/fesm2022/shirkasoft-ui-components-tooltip.mjs.map +1 -0
  47. package/fesm2022/shirkasoft-ui-components-utils.mjs +64 -0
  48. package/fesm2022/shirkasoft-ui-components-utils.mjs.map +1 -0
  49. package/fesm2022/shirkasoft-ui-components-wizard.mjs +167 -0
  50. package/fesm2022/shirkasoft-ui-components-wizard.mjs.map +1 -0
  51. package/fesm2022/shirkasoft-ui-components.mjs +0 -5729
  52. package/fesm2022/shirkasoft-ui-components.mjs.map +1 -1
  53. package/package.json +101 -1
  54. package/types/shirkasoft-ui-components-breadcrumb.d.ts +68 -0
  55. package/types/shirkasoft-ui-components-button.d.ts +59 -0
  56. package/types/shirkasoft-ui-components-chart.d.ts +65 -0
  57. package/types/shirkasoft-ui-components-confirm-dialog.d.ts +88 -0
  58. package/types/shirkasoft-ui-components-date-picker.d.ts +200 -0
  59. package/types/shirkasoft-ui-components-fieldset.d.ts +72 -0
  60. package/types/shirkasoft-ui-components-file-upload.d.ts +87 -0
  61. package/types/shirkasoft-ui-components-knob.d.ts +69 -0
  62. package/types/shirkasoft-ui-components-loading.d.ts +94 -0
  63. package/types/shirkasoft-ui-components-modal.d.ts +139 -0
  64. package/types/shirkasoft-ui-components-notification.d.ts +82 -0
  65. package/types/shirkasoft-ui-components-price-input.d.ts +41 -0
  66. package/types/shirkasoft-ui-components-rail-sidebar.d.ts +121 -0
  67. package/types/shirkasoft-ui-components-select.d.ts +182 -0
  68. package/types/shirkasoft-ui-components-sidebar.d.ts +106 -0
  69. package/types/shirkasoft-ui-components-skeleton.d.ts +36 -0
  70. package/types/shirkasoft-ui-components-table.d.ts +293 -0
  71. package/types/shirkasoft-ui-components-tabs.d.ts +102 -0
  72. package/types/shirkasoft-ui-components-tag.d.ts +31 -0
  73. package/types/shirkasoft-ui-components-text-field.d.ts +120 -0
  74. package/types/shirkasoft-ui-components-timeline.d.ts +178 -0
  75. package/types/shirkasoft-ui-components-toggle.d.ts +48 -0
  76. package/types/shirkasoft-ui-components-tooltip.d.ts +47 -0
  77. package/types/shirkasoft-ui-components-utils.d.ts +9 -0
  78. package/types/shirkasoft-ui-components-wizard.d.ts +101 -0
  79. package/types/shirkasoft-ui-components.d.ts +1 -2333
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shirkasoft-ui-components-loading.mjs","sources":["../../../projects/ui-components/loading/loading-spinner.component.ts","../../../projects/ui-components/loading/loading-bar.component.ts","../../../projects/ui-components/loading/loading-overlay.component.ts","../../../projects/ui-components/loading/loading-dots.component.ts","../../../projects/ui-components/loading/shirkasoft-ui-components-loading.ts"],"sourcesContent":["import { Component, input, ChangeDetectionStrategy } from '@angular/core';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/** Circular indeterminate spinner. */\n@Component({\n selector: 'shk-loading-spinner',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div\n class=\"shk-loading-spinner\"\n [style]=\"{\n width: size(),\n height: size(),\n }\"\n role=\"status\"\n aria-label=\"Cargando\"\n >\n <div\n class=\"shk-loading-spinner-circle\"\n [style]=\"{\n borderWidth: thickness(),\n borderTopColor: color() || undefined,\n }\"\n ></div>\n </div>\n @if (label()) {\n <span class=\"shk-loading-spinner-label\">{{ label() }}</span>\n }\n `,\n styles: [\n `\n :host {\n display: inline-flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n }\n .shk-loading-spinner {\n display: inline-block;\n }\n .shk-loading-spinner-circle {\n width: 100%;\n height: 100%;\n border-radius: 9999px;\n border-style: solid;\n border-color: color-mix(in srgb, var(--shk-primary-600) 20%, transparent);\n border-top-color: var(--shk-primary-600);\n animation: shk-loading-spin 0.8s linear infinite;\n }\n .shk-loading-spinner-label {\n font-size: 0.8125rem;\n color: var(--shk-surface-500);\n }\n @keyframes shk-loading-spin {\n to {\n transform: rotate(360deg);\n }\n }\n `,\n ],\n})\nexport class LoadingSpinnerComponent {\n /** Diameter of the spinner. */\n size = input<string>('2rem');\n /** Border thickness in px. */\n thickness = input<number>(3);\n /** Color of the moving arc. Defaults to the primary token. */\n color = input<string>('');\n /** Optional text shown under the spinner. */\n label = input<string>('');\n}\n","import { Component, computed, input, ChangeDetectionStrategy } from '@angular/core';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/** Progress bar with an indeterminate sweep or a determinate percentage. */\n@Component({\n selector: 'shk-loading-bar',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div\n class=\"shk-loading-bar\"\n [class.shk-loading-bar-indeterminate]=\"indeterminate()\"\n [style]=\"{ height: height(), borderRadius: rounded() ? '9999px' : undefined }\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"indeterminate() ? undefined : progress()\"\n aria-label=\"Progreso\"\n >\n <div\n class=\"shk-loading-bar-fill\"\n [style]=\"fillStyle()\"\n [style.background-color]=\"color() || undefined\"\n [style.border-radius]=\"rounded() ? '9999px' : undefined\"\n ></div>\n </div>\n `,\n styles: [\n `\n .shk-loading-bar {\n width: 100%;\n position: relative;\n overflow: hidden;\n background-color: var(--shk-surface-200);\n }\n .shk-loading-bar-fill {\n height: 100%;\n background-color: var(--shk-primary-600);\n transition: width 0.3s ease-in-out;\n }\n .shk-loading-bar-indeterminate .shk-loading-bar-fill {\n width: 40%;\n animation: shk-loading-bar-sweep 1.2s ease-in-out infinite;\n }\n @keyframes shk-loading-bar-sweep {\n 0% {\n transform: translateX(-100%);\n }\n 100% {\n transform: translateX(350%);\n }\n }\n `,\n ],\n})\nexport class LoadingBarComponent {\n /** Height of the bar. */\n height = input<string>('0.25rem');\n /** When true the bar animates without a known percentage. */\n indeterminate = input<boolean>(true);\n /** Current progress 0-100 when `indeterminate` is false. */\n progress = input<number>(0);\n /** Fill color. Defaults to the primary token. */\n color = input<string>('');\n /** Renders fully rounded ends. */\n rounded = input<boolean>(true);\n\n /** Fill width/style for the determinate mode, empty for indeterminate. */\n protected fillStyle = computed(() => {\n if (this.indeterminate()) return {};\n return { width: `${Math.max(0, Math.min(100, this.progress()))}%` };\n });\n}\n","import { Component, input, ChangeDetectionStrategy } from '@angular/core';\nimport { LoadingSpinnerComponent } from './loading-spinner.component';\n\n/** Backdrop style behind the overlay: none, light or dark. */\nexport type LoadingOverlayBackdrop = 'transparent' | 'light' | 'dark';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/** Wraps content and shows a centered spinner over it while `visible` is true. */\n@Component({\n selector: 'shk-loading-overlay',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [LoadingSpinnerComponent],\n template: `\n <div\n class=\"shk-loading-overlay\"\n [class.shk-loading-overlay-light]=\"backdrop() === 'light'\"\n [class.shk-loading-overlay-dark]=\"backdrop() === 'dark'\"\n >\n <ng-content></ng-content>\n @if (visible()) {\n <div class=\"shk-loading-overlay-layer\">\n <shk-loading-spinner [size]=\"spinnerSize()\" [color]=\"color()\" [label]=\"message()\" />\n </div>\n }\n </div>\n `,\n styles: [\n `\n :host {\n display: block;\n }\n .shk-loading-overlay {\n position: relative;\n min-height: 1.5rem;\n }\n .shk-loading-overlay-layer {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10;\n }\n .shk-loading-overlay-light .shk-loading-overlay-layer {\n background-color: rgba(255, 255, 255, 0.65);\n }\n .dark .shk-loading-overlay-light .shk-loading-overlay-layer {\n background-color: rgba(0, 0, 0, 0.55);\n }\n .shk-loading-overlay-dark .shk-loading-overlay-layer {\n background-color: rgba(0, 0, 0, 0.4);\n }\n `,\n ],\n})\nexport class LoadingOverlayComponent {\n /** Controls whether the spinner layer is shown. */\n visible = input<boolean>(false);\n /** Optional text under the spinner. */\n message = input<string>('');\n /** Diameter of the spinner. */\n spinnerSize = input<string>('2.5rem');\n /** Spinner color. Defaults to the primary token. */\n color = input<string>('');\n /** Backdrop behind the spinner. */\n backdrop = input<LoadingOverlayBackdrop>('transparent');\n}\n","import { Component, computed, input, ChangeDetectionStrategy } from '@angular/core';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/** Bouncing dots loading indicator. */\n@Component({\n selector: 'shk-loading-dots',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <span class=\"shk-loading-dots\" role=\"status\" aria-label=\"Cargando\">\n @for (dot of dots(); track $index) {\n <span\n class=\"shk-loading-dot\"\n [style]=\"{\n width: size(),\n height: size(),\n backgroundColor: color() || undefined,\n animationDelay: $index * 0.12 + 's',\n }\"\n ></span>\n }\n </span>\n @if (label()) {\n <span class=\"shk-loading-dots-label\">{{ label() }}</span>\n }\n `,\n styles: [\n `\n :host {\n display: inline-flex;\n align-items: center;\n gap: 0.5rem;\n }\n .shk-loading-dots {\n display: inline-flex;\n align-items: center;\n gap: 0.25rem;\n }\n .shk-loading-dot {\n border-radius: 9999px;\n background-color: var(--shk-primary-600);\n animation: shk-loading-dots-bounce 1.4s ease-in-out infinite;\n }\n .shk-loading-dots-label {\n font-size: 0.8125rem;\n color: var(--shk-surface-500);\n }\n @keyframes shk-loading-dots-bounce {\n 0%,\n 80%,\n 100% {\n transform: scale(0.6);\n opacity: 0.5;\n }\n 40% {\n transform: scale(1);\n opacity: 1;\n }\n }\n `,\n ],\n})\nexport class LoadingDotsComponent {\n /** Diameter of each dot. */\n size = input<string>('0.5rem');\n /** Dot color. Defaults to the primary token. */\n color = input<string>('');\n /** Number of dots. */\n count = input<number>(3);\n /** Optional text shown next to the dots. */\n label = input<string>('');\n\n /** Array of dot indices to render based on the `count` input. */\n protected dots = computed(() => Array.from({ length: Math.max(1, this.count()) }));\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,290 @@
1
+ import * as i0 from '@angular/core';
2
+ import { signal, inject, DestroyRef, computed, Injectable, ChangeDetectorRef, viewChild, ViewContainerRef, effect, untracked, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import { LucideX, LucideDynamicIcon } from '@lucide/angular';
5
+ import { FormControl, FormGroup } from '@angular/forms';
6
+ import { TranslocoService } from '@jsverse/transloco';
7
+ import { Router } from '@angular/router';
8
+ import { NotificationService } from 'shirkasoft-ui-components/notification';
9
+ import { getIcon } from 'shirkasoft-ui-components/utils';
10
+
11
+ /**
12
+ * Global modal manager. Opens modals on a stack, exposing reactive access to
13
+ * the current modal and the top-most opened config.
14
+ */
15
+ class ModalService {
16
+ constructor() {
17
+ /** Stack of open modals (top-most renders on top). */
18
+ this.stackSignal = signal([], ...(ngDevMode ? [{ debugName: "stackSignal" }] : /* istanbul ignore next */ []));
19
+ /** Counter emitted on each close, used to trigger close animations. */
20
+ this.closeRequestSignal = signal(0, ...(ngDevMode ? [{ debugName: "closeRequestSignal" }] : /* istanbul ignore next */ []));
21
+ this.router = inject(Router);
22
+ this.destroyRef = inject(DestroyRef);
23
+ /** Reactive list of open modals. */
24
+ this.modalStack = computed(() => this.stackSignal(), ...(ngDevMode ? [{ debugName: "modalStack" }] : /* istanbul ignore next */ []));
25
+ /** Top-most modal on the stack, or null. */
26
+ this.currentModal = computed(() => {
27
+ const stack = this.stackSignal();
28
+ return stack.length > 0 ? stack[stack.length - 1] : null;
29
+ }, ...(ngDevMode ? [{ debugName: "currentModal" }] : /* istanbul ignore next */ []));
30
+ /** Reactive close-request counter. */
31
+ this.closeRequest = computed(() => this.closeRequestSignal(), ...(ngDevMode ? [{ debugName: "closeRequest" }] : /* istanbul ignore next */ []));
32
+ // Close all modals on navigation and on service destruction.
33
+ this.router.events.subscribe(() => {
34
+ this.stackSignal.set([]);
35
+ });
36
+ this.destroyRef.onDestroy(() => this.stackSignal.set([]));
37
+ }
38
+ /** Opens a new modal on top of the stack. */
39
+ open(config) {
40
+ this.stackSignal.update((stack) => [...stack, config]);
41
+ }
42
+ /** Alias of `close()` used by the accept button. */
43
+ accept() {
44
+ this.close();
45
+ }
46
+ /** Closes the top-most modal, invoking its onClose callback. */
47
+ close() {
48
+ const stack = this.stackSignal();
49
+ if (stack.length > 0) {
50
+ stack[stack.length - 1]?.onClose?.();
51
+ this.stackSignal.set(stack.slice(0, -1));
52
+ this.closeRequestSignal.update((v) => v + 1);
53
+ }
54
+ }
55
+ /** Closes all open modals at once. */
56
+ clear() {
57
+ this.stackSignal.set([]);
58
+ }
59
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ModalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
60
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ModalService, providedIn: 'root' }); }
61
+ }
62
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ModalService, decorators: [{
63
+ type: Injectable,
64
+ args: [{ providedIn: 'root' }]
65
+ }], ctorParameters: () => [] });
66
+
67
+ /**
68
+ * Shirkasoft UI Components.
69
+ * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).
70
+ * Belongs to Shirkasoft.
71
+ */
72
+ /**
73
+ * Modal dialog that renders a dynamically loaded component, tracks its
74
+ * form validity and submit outputs, and delegates accept/cancel to the
75
+ * shared ModalService.
76
+ */
77
+ class ModalComponent {
78
+ constructor() {
79
+ this.getIcon = (name) => getIcon(name, LucideX);
80
+ this.notificationSrv = inject(NotificationService);
81
+ this.destroyRef = inject(DestroyRef);
82
+ this.modalSrv = inject(ModalService);
83
+ this.transloco = inject(TranslocoService);
84
+ this.cdr = inject(ChangeDetectorRef);
85
+ /** Reference where the dynamic content is rendered. */
86
+ this.container = viewChild('dynamicContent', { ...(ngDevMode ? { debugName: "container" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
87
+ /** Configuration of the modal currently open (from the service). */
88
+ this.currentConfig = signal(null, ...(ngDevMode ? [{ debugName: "currentConfig" }] : /* istanbul ignore next */ []));
89
+ /** Modal title. */
90
+ this.title = signal('', ...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
91
+ /** Whether the modal is visible. */
92
+ this.visible = signal(false, ...(ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []));
93
+ /** Generic loading flag for the footer actions. */
94
+ this.loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : /* istanbul ignore next */ []));
95
+ /** Whether the accept action is being processed. */
96
+ this.isProcessing = signal(false, ...(ngDevMode ? [{ debugName: "isProcessing" }] : /* istanbul ignore next */ []));
97
+ /** Whether the modal is currently expanded to fullscreen. */
98
+ this.isExpanded = signal(false, ...(ngDevMode ? [{ debugName: "isExpanded" }] : /* istanbul ignore next */ []));
99
+ /** True when the dynamic component reports a valid form. */
100
+ this.isFormValid = signal(false, ...(ngDevMode ? [{ debugName: "isFormValid" }] : /* istanbul ignore next */ []));
101
+ /** Reference to the dynamically created component. */
102
+ this.componentRef = null;
103
+ /** Subscriptions to the dynamic component outputs. */
104
+ this.subscriptions = [];
105
+ /** Width of the modal (fullscreen when expanded). */
106
+ this.computedModalWidth = computed(() => {
107
+ return this.isExpanded() ? '100vw' : (this.currentConfig()?.width ?? '560px');
108
+ }, ...(ngDevMode ? [{ debugName: "computedModalWidth" }] : /* istanbul ignore next */ []));
109
+ /** Whether the footer buttons should be rendered. */
110
+ this.modalButtonsVisible = computed(() => this.currentConfig()?.showButtons ?? true, ...(ngDevMode ? [{ debugName: "modalButtonsVisible" }] : /* istanbul ignore next */ []));
111
+ /** Whether the expand/fullscreen button is shown. */
112
+ this.showExpandButton = computed(() => this.currentConfig()?.showExpandButton ?? false, ...(ngDevMode ? [{ debugName: "showExpandButton" }] : /* istanbul ignore next */ []));
113
+ /** Resolved cancel button label. */
114
+ this.cancelLabel = computed(() => this.currentConfig()?.cancelLabel || 'Cancelar', ...(ngDevMode ? [{ debugName: "cancelLabel" }] : /* istanbul ignore next */ []));
115
+ /** Resolved accept button label. */
116
+ this.acceptLabel = computed(() => this.currentConfig()?.acceptLabel || 'Aceptar', ...(ngDevMode ? [{ debugName: "acceptLabel" }] : /* istanbul ignore next */ []));
117
+ effect(() => {
118
+ const config = this.modalSrv.currentModal();
119
+ if (config) {
120
+ this.currentConfig.set(config);
121
+ this.title.set(config.title);
122
+ this.isExpanded.set(false);
123
+ this.visible.set(true);
124
+ this.isProcessing.set(false);
125
+ this.loading.set(false);
126
+ this.cdr.markForCheck();
127
+ setTimeout(() => {
128
+ untracked(() => this.loadComponent(config));
129
+ });
130
+ }
131
+ else {
132
+ this.visible.set(false);
133
+ this.currentConfig.set(null);
134
+ this.cdr.markForCheck();
135
+ }
136
+ });
137
+ this.destroyRef.onDestroy(() => this.cleanup());
138
+ }
139
+ /** Updates visibility when the backdrop/close controls change. */
140
+ onVisibleChange(show) {
141
+ this.visible.set(show);
142
+ if (!show) {
143
+ this.closeModal();
144
+ }
145
+ this.cdr.markForCheck();
146
+ }
147
+ /** Creates the dynamic component and wires its form/submit outputs. */
148
+ loadComponent(config) {
149
+ const containerRef = this.container();
150
+ if (!containerRef)
151
+ return;
152
+ this.cleanup();
153
+ containerRef.clear();
154
+ this.componentRef = containerRef.createComponent(config.component);
155
+ if (config.data) {
156
+ Object.entries(config.data).forEach(([key, value]) => {
157
+ this.componentRef?.setInput(key, value);
158
+ });
159
+ }
160
+ const instance = this.componentRef.instance;
161
+ this.subscribeToOutput(instance.formValid, (valid) => {
162
+ this.isFormValid.set(valid);
163
+ this.cdr.markForCheck();
164
+ });
165
+ this.subscribeToOutput(instance.submitSuccess, () => this.handleSubmit(true));
166
+ this.subscribeToOutput(instance.submitError, () => this.handleSubmit(false));
167
+ this.componentRef.changeDetectorRef.markForCheck();
168
+ this.cdr.markForCheck();
169
+ }
170
+ /** Subscribes to a dynamic component output if it exists. */
171
+ subscribeToOutput(output, callback) {
172
+ if (output?.subscribe) {
173
+ this.subscriptions.push(output.subscribe(callback));
174
+ }
175
+ }
176
+ /** Finalizes the submit flow, accepting the modal on success. */
177
+ handleSubmit(success) {
178
+ this.isProcessing.set(false);
179
+ this.loading.set(false);
180
+ this.cdr.markForCheck();
181
+ if (success) {
182
+ untracked(() => this.modalSrv.accept());
183
+ }
184
+ }
185
+ /** Closes the modal, calling the dynamic component's `handleCancel` if any. */
186
+ closeModal() {
187
+ if (this.componentRef?.instance?.handleCancel) {
188
+ this.componentRef.instance.handleCancel();
189
+ }
190
+ this.doClose();
191
+ }
192
+ /** Performs the actual close sequence and cleanup. */
193
+ doClose() {
194
+ this.visible.set(false);
195
+ this.isProcessing.set(false);
196
+ this.loading.set(false);
197
+ if (this.isExpanded()) {
198
+ this.isExpanded.set(false);
199
+ }
200
+ this.cdr.markForCheck();
201
+ setTimeout(() => {
202
+ this.cleanup();
203
+ this.modalSrv.close();
204
+ }, 100);
205
+ }
206
+ /** Toggles between normal width and fullscreen. */
207
+ toggleExpand() {
208
+ this.isExpanded.update((v) => !v);
209
+ this.cdr.markForCheck();
210
+ }
211
+ /** Validates the dynamic component form and triggers its `onSubmit`. */
212
+ onAccept() {
213
+ if (!this.componentRef || !this.isDynamicComponent(this.componentRef.instance))
214
+ return;
215
+ if (this.isProcessing())
216
+ return;
217
+ const instance = this.componentRef.instance;
218
+ const form = this.getForm(instance);
219
+ if (form) {
220
+ this.markAllAsTouched(form);
221
+ this.componentRef.changeDetectorRef.markForCheck();
222
+ this.cdr.markForCheck();
223
+ if (this.hasRealErrors(form)) {
224
+ this.notificationSrv.addNotification(this.transloco.translate('modal.formInvalid'), 'warning');
225
+ return;
226
+ }
227
+ }
228
+ this.isProcessing.set(true);
229
+ this.loading.set(true);
230
+ this.cdr.markForCheck();
231
+ instance.onSubmit();
232
+ }
233
+ /** Resolves the dynamic component's form (property or getter function). */
234
+ getForm(instance) {
235
+ if (!instance['form'])
236
+ return null;
237
+ return typeof instance['form'] === 'function'
238
+ ? instance['form']()
239
+ : instance['form'];
240
+ }
241
+ /** Recursively checks for real validation errors (ignoring 'warning'). */
242
+ hasRealErrors(control) {
243
+ if (control instanceof FormControl) {
244
+ const errors = control.errors;
245
+ return errors
246
+ ? Object.keys(errors).some((key) => key !== 'warning')
247
+ : false;
248
+ }
249
+ const groupErrors = control.errors;
250
+ if (groupErrors &&
251
+ Object.keys(groupErrors).some((key) => key !== 'warning')) {
252
+ return true;
253
+ }
254
+ return Object.values(control.controls).some((child) => this.hasRealErrors(child));
255
+ }
256
+ /** Marks a form (and all its descendants) as touched. */
257
+ markAllAsTouched(control) {
258
+ control.markAsTouched();
259
+ control.updateValueAndValidity({ onlySelf: true, emitEvent: true });
260
+ if (control instanceof FormGroup) {
261
+ Object.values(control.controls).forEach((child) => this.markAllAsTouched(child));
262
+ }
263
+ }
264
+ /** True when the component exposes both `onSubmit` and a `form`. */
265
+ isDynamicComponent(instance) {
266
+ return typeof instance?.onSubmit === 'function' && instance?.form !== undefined;
267
+ }
268
+ /** Unsubscribes outputs and destroys the dynamic component. */
269
+ cleanup() {
270
+ this.subscriptions.forEach((sub) => sub.unsubscribe());
271
+ this.subscriptions = [];
272
+ if (this.componentRef) {
273
+ this.componentRef.destroy();
274
+ this.componentRef = null;
275
+ }
276
+ }
277
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
278
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: ModalComponent, isStandalone: true, selector: "shk-modal", viewQueries: [{ propertyName: "container", first: true, predicate: ["dynamicContent"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "@if (visible()) {\n <div\n class=\"fixed inset-0 bg-black/40 backdrop-blur-sm flex items-center justify-center z-40 p-4 pt-4 overflow-y-auto _shk-scrollbar\"\n (click)=\"closeModal()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-100)] rounded-xl shadow-2xl overflow-hidden flex flex-col animate-in fade-in zoom-in duration-200\"\n [class.w-[95vw]]=\"isExpanded()\"\n [class.h-[90vh]]=\"isExpanded()\"\n [class.w-full]=\"!isExpanded()\"\n [style.max-width]=\"isExpanded() ? undefined : computedModalWidth()\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"h-1.5 w-full _shk-gradient-emerald shrink-0\"></div>\n\n <div class=\"flex items-center justify-between px-6 pt-4 pb-2 shrink-0\">\n <span class=\"font-semibold text-lg _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">{{ title() }}</span>\n <div class=\"flex items-center gap-2\">\n @if (showExpandButton()) {\n <button\n type=\"button\"\n (click)=\"toggleExpand()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n @if (isExpanded()) {\n <svg [lucideIcon]=\"getIcon('minimize-2')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('maximize-2')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-y-auto px-6 py-4 flex-1 max-h-[70vh] _shk-scrollbar\">\n <ng-container #dynamicContent></ng-container>\n </div>\n\n @if (modalButtonsVisible()) {\n <hr class=\"border-t _shk-border dark:[border-color:var(--shk-surface-200)] shrink-0\" />\n <div class=\"flex justify-end gap-3 px-6 py-4 shrink-0\">\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-600)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-300)] rounded-lg transition-colors flex items-center gap-2 disabled:opacity-50\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n <button\n type=\"button\"\n (click)=\"onAccept()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-white _shk-bg-emerald hover:[background-color:var(--shk-emerald-700)] rounded-lg shadow-md transition-all flex items-center gap-2 disabled:opacity-50\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('check')\" class=\"w-4 h-4\"></svg>\n }\n {{ acceptLabel() }}\n </button>\n </div>\n }\n </div>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
279
+ }
280
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: ModalComponent, decorators: [{
281
+ type: Component,
282
+ args: [{ selector: 'shk-modal', standalone: true, imports: [CommonModule, LucideDynamicIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (visible()) {\n <div\n class=\"fixed inset-0 bg-black/40 backdrop-blur-sm flex items-center justify-center z-40 p-4 pt-4 overflow-y-auto _shk-scrollbar\"\n (click)=\"closeModal()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-100)] rounded-xl shadow-2xl overflow-hidden flex flex-col animate-in fade-in zoom-in duration-200\"\n [class.w-[95vw]]=\"isExpanded()\"\n [class.h-[90vh]]=\"isExpanded()\"\n [class.w-full]=\"!isExpanded()\"\n [style.max-width]=\"isExpanded() ? undefined : computedModalWidth()\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"h-1.5 w-full _shk-gradient-emerald shrink-0\"></div>\n\n <div class=\"flex items-center justify-between px-6 pt-4 pb-2 shrink-0\">\n <span class=\"font-semibold text-lg _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">{{ title() }}</span>\n <div class=\"flex items-center gap-2\">\n @if (showExpandButton()) {\n <button\n type=\"button\"\n (click)=\"toggleExpand()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n @if (isExpanded()) {\n <svg [lucideIcon]=\"getIcon('minimize-2')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('maximize-2')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-y-auto px-6 py-4 flex-1 max-h-[70vh] _shk-scrollbar\">\n <ng-container #dynamicContent></ng-container>\n </div>\n\n @if (modalButtonsVisible()) {\n <hr class=\"border-t _shk-border dark:[border-color:var(--shk-surface-200)] shrink-0\" />\n <div class=\"flex justify-end gap-3 px-6 py-4 shrink-0\">\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-600)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-300)] rounded-lg transition-colors flex items-center gap-2 disabled:opacity-50\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n <button\n type=\"button\"\n (click)=\"onAccept()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-white _shk-bg-emerald hover:[background-color:var(--shk-emerald-700)] rounded-lg shadow-md transition-all flex items-center gap-2 disabled:opacity-50\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('check')\" class=\"w-4 h-4\"></svg>\n }\n {{ acceptLabel() }}\n </button>\n </div>\n }\n </div>\n </div>\n}\n" }]
283
+ }], ctorParameters: () => [], propDecorators: { container: [{ type: i0.ViewChild, args: ['dynamicContent', { ...{ read: ViewContainerRef }, isSignal: true }] }] } });
284
+
285
+ /**
286
+ * Generated bundle index. Do not edit.
287
+ */
288
+
289
+ export { ModalComponent, ModalService };
290
+ //# sourceMappingURL=shirkasoft-ui-components-modal.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shirkasoft-ui-components-modal.mjs","sources":["../../../projects/ui-components/modal/modal.service.ts","../../../projects/ui-components/modal/modal.component.ts","../../../projects/ui-components/modal/modal.component.html","../../../projects/ui-components/modal/shirkasoft-ui-components-modal.ts"],"sourcesContent":["import { Injectable, Type, signal, computed, inject, DestroyRef } from '@angular/core';\nimport { Router } from '@angular/router';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/** Options for opening a modal through the service. */\nexport interface ModalConfig {\n /** Title shown in the modal header. */\n title: string;\n /** Component rendered inside the modal body. */\n component: Type<any>;\n /** Data passed to the modal component via inputs. */\n data?: Record<string, any>;\n /** Modal width (CSS value). */\n width?: string;\n /** Whether the accept/cancel buttons are shown. */\n showButtons?: boolean;\n /** Whether the expand (fullscreen) button is shown. */\n showExpandButton?: boolean;\n /** Label of the accept button. */\n acceptLabel?: string;\n /** Label of the cancel button. */\n cancelLabel?: string;\n /** Optional callback invoked when the modal closes. */\n onClose?: () => void;\n}\n\n/**\n * Global modal manager. Opens modals on a stack, exposing reactive access to\n * the current modal and the top-most opened config.\n */\n@Injectable({ providedIn: 'root' })\nexport class ModalService {\n /** Stack of open modals (top-most renders on top). */\n private stackSignal = signal<ModalConfig[]>([]);\n /** Counter emitted on each close, used to trigger close animations. */\n private closeRequestSignal = signal<number>(0);\n private router = inject(Router);\n private destroyRef = inject(DestroyRef);\n\n constructor() {\n // Close all modals on navigation and on service destruction.\n this.router.events.subscribe(() => {\n this.stackSignal.set([]);\n });\n this.destroyRef.onDestroy(() => this.stackSignal.set([]));\n }\n\n /** Reactive list of open modals. */\n modalStack = computed(() => this.stackSignal());\n /** Top-most modal on the stack, or null. */\n currentModal = computed<ModalConfig | null>(() => {\n const stack = this.stackSignal();\n return stack.length > 0 ? stack[stack.length - 1] : null;\n });\n /** Reactive close-request counter. */\n closeRequest = computed(() => this.closeRequestSignal());\n\n /** Opens a new modal on top of the stack. */\n open(config: ModalConfig) {\n this.stackSignal.update((stack) => [...stack, config]);\n }\n\n /** Alias of `close()` used by the accept button. */\n accept() {\n this.close();\n }\n\n /** Closes the top-most modal, invoking its onClose callback. */\n close() {\n const stack = this.stackSignal();\n if (stack.length > 0) {\n stack[stack.length - 1]?.onClose?.();\n this.stackSignal.set(stack.slice(0, -1));\n this.closeRequestSignal.update((v) => v + 1);\n }\n }\n\n /** Closes all open modals at once. */\n clear() {\n this.stackSignal.set([]);\n }\n}","import {\n Component,\n viewChild,\n ViewContainerRef,\n ComponentRef,\n inject,\n effect,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n signal,\n DestroyRef,\n computed,\n untracked,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n LucideDynamicIcon,\n LucideX,\n} from '@lucide/angular';\nimport { Subscription } from 'rxjs';\nimport { FormControl, FormGroup } from '@angular/forms';\nimport { TranslocoService } from '@jsverse/transloco';\nimport { ModalService, ModalConfig } from './modal.service';\nimport { NotificationService } from 'shirkasoft-ui-components/notification';\nimport { getIcon as getIconFromCentral } from 'shirkasoft-ui-components/utils';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/**\n * Modal dialog that renders a dynamically loaded component, tracks its\n * form validity and submit outputs, and delegates accept/cancel to the\n * shared ModalService.\n */\n@Component({\n selector: 'shk-modal',\n standalone: true,\n imports: [CommonModule, LucideDynamicIcon],\n templateUrl: './modal.component.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ModalComponent {\n protected getIcon = (name: any) => getIconFromCentral(name, LucideX);\n\n private notificationSrv = inject(NotificationService);\n private destroyRef = inject(DestroyRef);\n private modalSrv = inject(ModalService);\n private transloco = inject(TranslocoService);\n private cdr = inject(ChangeDetectorRef);\n\n /** Reference where the dynamic content is rendered. */\n container = viewChild('dynamicContent', { read: ViewContainerRef });\n\n /** Configuration of the modal currently open (from the service). */\n currentConfig = signal<ModalConfig | null>(null);\n /** Modal title. */\n title = signal('');\n /** Whether the modal is visible. */\n visible = signal(false);\n /** Generic loading flag for the footer actions. */\n loading = signal(false);\n /** Whether the accept action is being processed. */\n isProcessing = signal(false);\n /** Whether the modal is currently expanded to fullscreen. */\n isExpanded = signal(false);\n /** True when the dynamic component reports a valid form. */\n isFormValid = signal(false);\n\n /** Reference to the dynamically created component. */\n componentRef: ComponentRef<any> | null = null;\n /** Subscriptions to the dynamic component outputs. */\n private subscriptions: Subscription[] = [];\n\n /** Width of the modal (fullscreen when expanded). */\n computedModalWidth = computed(() => {\n return this.isExpanded() ? '100vw' : (this.currentConfig()?.width ?? '560px');\n });\n\n /** Whether the footer buttons should be rendered. */\n modalButtonsVisible = computed(() => this.currentConfig()?.showButtons ?? true);\n /** Whether the expand/fullscreen button is shown. */\n showExpandButton = computed(() => this.currentConfig()?.showExpandButton ?? false);\n /** Resolved cancel button label. */\n cancelLabel = computed(() => this.currentConfig()?.cancelLabel || 'Cancelar');\n /** Resolved accept button label. */\n acceptLabel = computed(() => this.currentConfig()?.acceptLabel || 'Aceptar');\n\n constructor() {\n effect(() => {\n const config = this.modalSrv.currentModal();\n if (config) {\n this.currentConfig.set(config);\n this.title.set(config.title);\n this.isExpanded.set(false);\n this.visible.set(true);\n this.isProcessing.set(false);\n this.loading.set(false);\n this.cdr.markForCheck();\n setTimeout(() => {\n untracked(() => this.loadComponent(config));\n });\n } else {\n this.visible.set(false);\n this.currentConfig.set(null);\n this.cdr.markForCheck();\n }\n });\n\n this.destroyRef.onDestroy(() => this.cleanup());\n }\n\n /** Updates visibility when the backdrop/close controls change. */\n onVisibleChange(show: boolean) {\n this.visible.set(show);\n if (!show) {\n this.closeModal();\n }\n this.cdr.markForCheck();\n }\n\n /** Creates the dynamic component and wires its form/submit outputs. */\n private loadComponent(config: ModalConfig) {\n const containerRef = this.container();\n if (!containerRef) return;\n\n this.cleanup();\n containerRef.clear();\n\n this.componentRef = containerRef.createComponent(config.component);\n\n if (config.data) {\n Object.entries(config.data).forEach(([key, value]) => {\n this.componentRef?.setInput(key, value);\n });\n }\n\n const instance = this.componentRef.instance;\n\n this.subscribeToOutput(instance.formValid, (valid: boolean) => {\n this.isFormValid.set(valid);\n this.cdr.markForCheck();\n });\n this.subscribeToOutput(instance.submitSuccess, () =>\n this.handleSubmit(true),\n );\n this.subscribeToOutput(instance.submitError, () =>\n this.handleSubmit(false),\n );\n\n this.componentRef.changeDetectorRef.markForCheck();\n this.cdr.markForCheck();\n }\n\n /** Subscribes to a dynamic component output if it exists. */\n private subscribeToOutput(output: any, callback: (value: any) => void) {\n if (output?.subscribe) {\n this.subscriptions.push(output.subscribe(callback));\n }\n }\n\n /** Finalizes the submit flow, accepting the modal on success. */\n private handleSubmit(success: boolean) {\n this.isProcessing.set(false);\n this.loading.set(false);\n this.cdr.markForCheck();\n if (success) {\n untracked(() => this.modalSrv.accept());\n }\n }\n\n /** Closes the modal, calling the dynamic component's `handleCancel` if any. */\n closeModal() {\n if (this.componentRef?.instance?.handleCancel) {\n this.componentRef.instance.handleCancel();\n }\n this.doClose();\n }\n\n /** Performs the actual close sequence and cleanup. */\n doClose() {\n this.visible.set(false);\n this.isProcessing.set(false);\n this.loading.set(false);\n if (this.isExpanded()) {\n this.isExpanded.set(false);\n }\n this.cdr.markForCheck();\n setTimeout(() => {\n this.cleanup();\n this.modalSrv.close();\n }, 100);\n }\n\n /** Toggles between normal width and fullscreen. */\n toggleExpand() {\n this.isExpanded.update((v) => !v);\n this.cdr.markForCheck();\n }\n\n /** Validates the dynamic component form and triggers its `onSubmit`. */\n onAccept() {\n if (!this.componentRef || !this.isDynamicComponent(this.componentRef.instance)) return;\n\n if (this.isProcessing()) return;\n\n const instance = this.componentRef.instance;\n const form = this.getForm(instance);\n\n if (form) {\n this.markAllAsTouched(form);\n this.componentRef.changeDetectorRef.markForCheck();\n this.cdr.markForCheck();\n\n if (this.hasRealErrors(form)) {\n this.notificationSrv.addNotification(\n this.transloco.translate('modal.formInvalid'),\n 'warning',\n );\n return;\n }\n }\n\n this.isProcessing.set(true);\n this.loading.set(true);\n this.cdr.markForCheck();\n instance.onSubmit();\n }\n\n /** Resolves the dynamic component's form (property or getter function). */\n private getForm(instance: any): FormGroup | null {\n if (!instance['form']) return null;\n return typeof instance['form'] === 'function'\n ? instance['form']()\n : instance['form'];\n }\n\n /** Recursively checks for real validation errors (ignoring 'warning'). */\n private hasRealErrors(control: FormGroup | FormControl): boolean {\n if (control instanceof FormControl) {\n const errors = control.errors;\n return errors\n ? Object.keys(errors).some((key) => key !== 'warning')\n : false;\n }\n\n const groupErrors = control.errors;\n if (\n groupErrors &&\n Object.keys(groupErrors).some((key) => key !== 'warning')\n ) {\n return true;\n }\n\n return Object.values(control.controls).some((child) =>\n this.hasRealErrors(child as any),\n );\n }\n\n /** Marks a form (and all its descendants) as touched. */\n private markAllAsTouched(control: FormGroup | FormControl): void {\n control.markAsTouched();\n control.updateValueAndValidity({ onlySelf: true, emitEvent: true });\n\n if (control instanceof FormGroup) {\n Object.values(control.controls).forEach((child) =>\n this.markAllAsTouched(child as any),\n );\n }\n }\n\n /** True when the component exposes both `onSubmit` and a `form`. */\n private isDynamicComponent(instance: any): boolean {\n return typeof instance?.onSubmit === 'function' && instance?.form !== undefined;\n }\n\n /** Unsubscribes outputs and destroys the dynamic component. */\n private cleanup() {\n this.subscriptions.forEach((sub) => sub.unsubscribe());\n this.subscriptions = [];\n\n if (this.componentRef) {\n this.componentRef.destroy();\n this.componentRef = null;\n }\n }\n}\n","@if (visible()) {\n <div\n class=\"fixed inset-0 bg-black/40 backdrop-blur-sm flex items-center justify-center z-40 p-4 pt-4 overflow-y-auto _shk-scrollbar\"\n (click)=\"closeModal()\"\n >\n <div\n class=\"bg-white dark:[background-color:var(--shk-surface-100)] rounded-xl shadow-2xl overflow-hidden flex flex-col animate-in fade-in zoom-in duration-200\"\n [class.w-[95vw]]=\"isExpanded()\"\n [class.h-[90vh]]=\"isExpanded()\"\n [class.w-full]=\"!isExpanded()\"\n [style.max-width]=\"isExpanded() ? undefined : computedModalWidth()\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"h-1.5 w-full _shk-gradient-emerald shrink-0\"></div>\n\n <div class=\"flex items-center justify-between px-6 pt-4 pb-2 shrink-0\">\n <span class=\"font-semibold text-lg _shk-text-surface-800 dark:[color:var(--shk-surface-800)]\">{{ title() }}</span>\n <div class=\"flex items-center gap-2\">\n @if (showExpandButton()) {\n <button\n type=\"button\"\n (click)=\"toggleExpand()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n @if (isExpanded()) {\n <svg [lucideIcon]=\"getIcon('minimize-2')\" class=\"w-4 h-4\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('maximize-2')\" class=\"w-4 h-4\"></svg>\n }\n </button>\n }\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n class=\"p-1.5 rounded-lg hover:[background-color:var(--shk-surface-100)] dark:hover:[background-color:var(--shk-surface-200)] _shk-text-surface-500 dark:[color:var(--shk-surface-500)] transition-colors\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n </div>\n\n <div class=\"overflow-y-auto px-6 py-4 flex-1 max-h-[70vh] _shk-scrollbar\">\n <ng-container #dynamicContent></ng-container>\n </div>\n\n @if (modalButtonsVisible()) {\n <hr class=\"border-t _shk-border dark:[border-color:var(--shk-surface-200)] shrink-0\" />\n <div class=\"flex justify-end gap-3 px-6 py-4 shrink-0\">\n <button\n type=\"button\"\n (click)=\"closeModal()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-surface-600 dark:[color:var(--shk-surface-600)] _shk-bg-surface-100 dark:[background-color:var(--shk-surface-200)] hover:[background-color:var(--shk-surface-200)] dark:hover:[background-color:var(--shk-surface-300)] rounded-lg transition-colors flex items-center gap-2 disabled:opacity-50\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n {{ cancelLabel() }}\n </button>\n <button\n type=\"button\"\n (click)=\"onAccept()\"\n [disabled]=\"loading()\"\n class=\"px-4 py-2 text-sm font-semibold _shk-text-white _shk-bg-emerald hover:[background-color:var(--shk-emerald-700)] rounded-lg shadow-md transition-all flex items-center gap-2 disabled:opacity-50\"\n >\n @if (loading()) {\n <svg [lucideIcon]=\"getIcon('loader-circle')\" class=\"w-4 h-4 animate-spin\"></svg>\n } @else {\n <svg [lucideIcon]=\"getIcon('check')\" class=\"w-4 h-4\"></svg>\n }\n {{ acceptLabel() }}\n </button>\n </div>\n }\n </div>\n </div>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["getIconFromCentral"],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ import * as i0 from '@angular/core';
2
+ import { signal, Injectable, input, inject, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import * as i1 from '@angular/common';
4
+ import { CommonModule } from '@angular/common';
5
+ import { LucideInfo, LucideDynamicIcon } from '@lucide/angular';
6
+ import { getIcon } from 'shirkasoft-ui-components/utils';
7
+
8
+ /**
9
+ * Central notification store. Components push/update/remove notifications
10
+ * reactively through signals for the notification component to render.
11
+ */
12
+ class NotificationService {
13
+ constructor() {
14
+ /** Reactive list of visible notifications. */
15
+ this.notificationsSignal = signal([], ...(ngDevMode ? [{ debugName: "notificationsSignal" }] : /* istanbul ignore next */ []));
16
+ /** Monotonic id counter for new notifications. */
17
+ this.currentId = 0;
18
+ /** Readonly reactive list of visible notifications. */
19
+ this.notifications = this.notificationsSignal.asReadonly();
20
+ }
21
+ /**
22
+ * Adds a notification and returns its id. When `showProgress` is false and
23
+ * `duration` is positive, it auto-removes after that many ms.
24
+ */
25
+ addNotification(message, type = 'info', showProgress = false, duration = 5000) {
26
+ const id = (++this.currentId).toString();
27
+ const notification = {
28
+ id,
29
+ message,
30
+ type,
31
+ progress: showProgress ? 0 : undefined,
32
+ showProgress,
33
+ };
34
+ this.notificationsSignal.update((notifications) => [
35
+ ...notifications,
36
+ notification,
37
+ ]);
38
+ if (duration > 0 && !showProgress) {
39
+ setTimeout(() => this.removeNotificationById(id), duration);
40
+ }
41
+ return id;
42
+ }
43
+ /** Updates a progress notification; auto-removes when progress hits 100. */
44
+ updateProgress(notificationId, progress) {
45
+ const currentNotifications = this.notificationsSignal();
46
+ const index = currentNotifications.findIndex((n) => n.id === notificationId);
47
+ if (index > -1 && currentNotifications[index].showProgress) {
48
+ const updatedProgress = Math.min(100, Math.max(0, progress));
49
+ this.notificationsSignal.update((notifications) => notifications.map((n, i) => i === index ? { ...n, progress: updatedProgress } : n));
50
+ if (progress >= 100) {
51
+ setTimeout(() => this.removeNotificationById(notificationId), 2000);
52
+ }
53
+ }
54
+ }
55
+ /** Removes the given notification. */
56
+ removeNotification(notification) {
57
+ this.removeNotificationById(notification.id);
58
+ }
59
+ /** Removes the notification with the given id. */
60
+ removeNotificationById(notificationId) {
61
+ this.notificationsSignal.update((notifications) => notifications.filter((n) => n.id !== notificationId));
62
+ }
63
+ /** Removes every visible notification. */
64
+ clearAll() {
65
+ this.notificationsSignal.set([]);
66
+ }
67
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: NotificationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
68
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: NotificationService, providedIn: 'root' }); }
69
+ }
70
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: NotificationService, decorators: [{
71
+ type: Injectable,
72
+ args: [{
73
+ providedIn: 'root',
74
+ }]
75
+ }] });
76
+
77
+ /**
78
+ * Shirkasoft UI Components.
79
+ * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).
80
+ * Belongs to Shirkasoft.
81
+ */
82
+ /**
83
+ * Toast notification host that renders the notifications pushed through the
84
+ * NotificationService in the configured position.
85
+ */
86
+ class NotificationComponent {
87
+ constructor() {
88
+ /** Position of the notification stack: center, right or left top. */
89
+ this.position = input('center-top', ...(ngDevMode ? [{ debugName: "position" }] : /* istanbul ignore next */ []));
90
+ this.notificationService = inject(NotificationService);
91
+ this.getIcon = (name) => getIcon(name, LucideInfo);
92
+ /** Maps each notification type to its internal icon name. */
93
+ this.iconMap = {
94
+ success: 'check',
95
+ error: 'circle-x',
96
+ info: 'info',
97
+ warning: 'triangle-alert',
98
+ };
99
+ /** Live list of active notifications. */
100
+ this.notifications = this.notificationService.notifications;
101
+ /** Notifications sorted with the newest first. */
102
+ this.sortedNotifications = computed(() => [...this.notifications()].reverse(), ...(ngDevMode ? [{ debugName: "sortedNotifications" }] : /* istanbul ignore next */ []));
103
+ /** Whether there are notifications to show. */
104
+ this.hasNotifications = computed(() => this.notifications().length > 0, ...(ngDevMode ? [{ debugName: "hasNotifications" }] : /* istanbul ignore next */ []));
105
+ /** CSS classes positioning the stack according to `position`. */
106
+ this.positionClass = computed(() => {
107
+ const base = 'fixed top-4 z-[9999] space-y-4 sm:space-y-6 sm:top-6 lg:top-8';
108
+ switch (this.position()) {
109
+ case 'right-top':
110
+ return `${base} right-4`;
111
+ case 'left-top':
112
+ return `${base} left-4`;
113
+ default:
114
+ return `${base} left-1/2 -translate-x-1/2`;
115
+ }
116
+ }, ...(ngDevMode ? [{ debugName: "positionClass" }] : /* istanbul ignore next */ []));
117
+ }
118
+ /** Resolves the icon name for a notification type. */
119
+ getNotificationIcon(type) {
120
+ return this.iconMap[type] || 'info';
121
+ }
122
+ /** Removes a notification through the service. */
123
+ removeNotification(notification) {
124
+ this.notificationService.removeNotification(notification);
125
+ }
126
+ /** Rounds the progress value of a notification. */
127
+ roundProgress(progress) {
128
+ return Math.round(progress || 0);
129
+ }
130
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: NotificationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
131
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.18", type: NotificationComponent, isStandalone: true, selector: "shk-notification", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div [class]=\"positionClass()\">\n @for (notification of sortedNotifications(); track notification.id) {\n <div\n [ngClass]=\"{\n 'bg-green-50/80 dark:bg-green-900/30 border-green-400 dark:border-green-600 text-green-800 dark:text-green-200':\n notification.type === 'success',\n 'bg-red-50/80 dark:bg-red-900/30 border-red-400 dark:border-red-600 text-red-800 dark:text-red-200':\n notification.type === 'error',\n 'bg-blue-50/80 dark:bg-blue-900/30 border-blue-400 dark:border-blue-600 text-blue-800 dark:text-blue-200':\n notification.type === 'info',\n 'bg-yellow-50/80 dark:bg-yellow-900/30 border-yellow-400 dark:border-yellow-500 text-yellow-800 dark:text-yellow-200':\n notification.type === 'warning',\n }\"\n class=\"flex items-center w-full min-w-[320px] max-w-xs sm:max-w-sm lg:max-w-md p-4 mb-4 border-l-4 rounded-lg shadow-lg backdrop-blur-sm transition-all duration-300 transform hover:scale-105 hover:shadow-xl\"\n role=\"alert\"\n >\n <div\n [ngClass]=\"{\n 'text-green-600': notification.type === 'success',\n 'text-red-600': notification.type === 'error',\n 'text-blue-600': notification.type === 'info',\n 'text-yellow-600': notification.type === 'warning',\n }\"\n class=\"inline-flex items-center justify-center flex-shrink-0 w-10 h-10 rounded-lg bg-opacity-10\"\n >\n <svg [lucideIcon]=\"getIcon(getNotificationIcon(notification.type))\" class=\"w-6 h-6\"></svg>\n </div>\n <div class=\"ms-4 flex-1 text-sm font-medium break-words\">\n {{ notification.message }}\n </div>\n <button\n type=\"button\"\n (click)=\"removeNotification(notification)\"\n aria-label=\"Close\"\n [ngClass]=\"{\n 'text-green-600 hover:text-green-800':\n notification.type === 'success',\n 'text-red-600 hover:text-red-800': notification.type === 'error',\n 'text-blue-600 hover:text-blue-800': notification.type === 'info',\n 'text-yellow-600 hover:text-yellow-800':\n notification.type === 'warning',\n }\"\n class=\"mx-2 -my-1.5 bg-transparent focus:outline-none\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n }\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
132
+ }
133
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.18", ngImport: i0, type: NotificationComponent, decorators: [{
134
+ type: Component,
135
+ args: [{ selector: 'shk-notification', standalone: true, imports: [CommonModule, LucideDynamicIcon], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"positionClass()\">\n @for (notification of sortedNotifications(); track notification.id) {\n <div\n [ngClass]=\"{\n 'bg-green-50/80 dark:bg-green-900/30 border-green-400 dark:border-green-600 text-green-800 dark:text-green-200':\n notification.type === 'success',\n 'bg-red-50/80 dark:bg-red-900/30 border-red-400 dark:border-red-600 text-red-800 dark:text-red-200':\n notification.type === 'error',\n 'bg-blue-50/80 dark:bg-blue-900/30 border-blue-400 dark:border-blue-600 text-blue-800 dark:text-blue-200':\n notification.type === 'info',\n 'bg-yellow-50/80 dark:bg-yellow-900/30 border-yellow-400 dark:border-yellow-500 text-yellow-800 dark:text-yellow-200':\n notification.type === 'warning',\n }\"\n class=\"flex items-center w-full min-w-[320px] max-w-xs sm:max-w-sm lg:max-w-md p-4 mb-4 border-l-4 rounded-lg shadow-lg backdrop-blur-sm transition-all duration-300 transform hover:scale-105 hover:shadow-xl\"\n role=\"alert\"\n >\n <div\n [ngClass]=\"{\n 'text-green-600': notification.type === 'success',\n 'text-red-600': notification.type === 'error',\n 'text-blue-600': notification.type === 'info',\n 'text-yellow-600': notification.type === 'warning',\n }\"\n class=\"inline-flex items-center justify-center flex-shrink-0 w-10 h-10 rounded-lg bg-opacity-10\"\n >\n <svg [lucideIcon]=\"getIcon(getNotificationIcon(notification.type))\" class=\"w-6 h-6\"></svg>\n </div>\n <div class=\"ms-4 flex-1 text-sm font-medium break-words\">\n {{ notification.message }}\n </div>\n <button\n type=\"button\"\n (click)=\"removeNotification(notification)\"\n aria-label=\"Close\"\n [ngClass]=\"{\n 'text-green-600 hover:text-green-800':\n notification.type === 'success',\n 'text-red-600 hover:text-red-800': notification.type === 'error',\n 'text-blue-600 hover:text-blue-800': notification.type === 'info',\n 'text-yellow-600 hover:text-yellow-800':\n notification.type === 'warning',\n }\"\n class=\"mx-2 -my-1.5 bg-transparent focus:outline-none\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n }\n</div>\n" }]
136
+ }], propDecorators: { position: [{ type: i0.Input, args: [{ isSignal: true, alias: "position", required: false }] }] } });
137
+
138
+ /**
139
+ * Generated bundle index. Do not edit.
140
+ */
141
+
142
+ export { NotificationComponent, NotificationService };
143
+ //# sourceMappingURL=shirkasoft-ui-components-notification.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shirkasoft-ui-components-notification.mjs","sources":["../../../projects/ui-components/notification/notification.service.ts","../../../projects/ui-components/notification/notification.component.ts","../../../projects/ui-components/notification/notification.component.html","../../../projects/ui-components/notification/shirkasoft-ui-components-notification.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/** Toast-style notification entry. */\nexport interface Notification {\n id: string;\n message: string;\n type: 'success' | 'error' | 'warning' | 'info';\n /** Current progress 0-100 when `showProgress` is true. */\n progress?: number;\n /** Whether the notification renders a progress indicator. */\n showProgress?: boolean;\n}\n\n/**\n * Central notification store. Components push/update/remove notifications\n * reactively through signals for the notification component to render.\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class NotificationService {\n /** Reactive list of visible notifications. */\n private notificationsSignal = signal<Notification[]>([]);\n /** Monotonic id counter for new notifications. */\n private currentId = 0;\n\n /** Readonly reactive list of visible notifications. */\n notifications = this.notificationsSignal.asReadonly();\n\n /**\n * Adds a notification and returns its id. When `showProgress` is false and\n * `duration` is positive, it auto-removes after that many ms.\n */\n addNotification(\n message: string,\n type: Notification['type'] = 'info',\n showProgress: boolean = false,\n duration: number = 5000\n ): string {\n const id = (++this.currentId).toString();\n const notification: Notification = {\n id,\n message,\n type,\n progress: showProgress ? 0 : undefined,\n showProgress,\n };\n\n this.notificationsSignal.update((notifications) => [\n ...notifications,\n notification,\n ]);\n\n if (duration > 0 && !showProgress) {\n setTimeout(() => this.removeNotificationById(id), duration);\n }\n\n return id;\n }\n\n /** Updates a progress notification; auto-removes when progress hits 100. */\n updateProgress(notificationId: string, progress: number) {\n const currentNotifications = this.notificationsSignal();\n const index = currentNotifications.findIndex(\n (n) => n.id === notificationId\n );\n\n if (index > -1 && currentNotifications[index].showProgress) {\n const updatedProgress = Math.min(100, Math.max(0, progress));\n\n this.notificationsSignal.update((notifications) =>\n notifications.map((n, i) =>\n i === index ? { ...n, progress: updatedProgress } : n\n )\n );\n\n if (progress >= 100) {\n setTimeout(() => this.removeNotificationById(notificationId), 2000);\n }\n }\n }\n\n /** Removes the given notification. */\n removeNotification(notification: Notification): void {\n this.removeNotificationById(notification.id);\n }\n\n /** Removes the notification with the given id. */\n removeNotificationById(notificationId: string): void {\n this.notificationsSignal.update((notifications) =>\n notifications.filter((n) => n.id !== notificationId)\n );\n }\n\n /** Removes every visible notification. */\n clearAll(): void {\n this.notificationsSignal.set([]);\n }\n}","import {\n Component,\n input,\n inject,\n ChangeDetectionStrategy,\n computed,\n} from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport {\n NotificationService,\n Notification,\n} from './notification.service';\nimport {\n LucideDynamicIcon,\n LucideInfo,\n LucideTriangleAlert,\n} from '@lucide/angular';\nimport { getIcon as getIconFromCentral } from 'shirkasoft-ui-components/utils';\n\nexport type NotificationPosition = 'center-top' | 'right-top' | 'left-top';\n\n/**\n * Shirkasoft UI Components.\n * Authors: Roberto Valladares Martin (Ansem13), Julio César García García (Sanjuli14).\n * Belongs to Shirkasoft.\n */\n\n/**\n * Toast notification host that renders the notifications pushed through the\n * NotificationService in the configured position.\n */\n@Component({\n selector: 'shk-notification',\n templateUrl: './notification.component.html',\n standalone: true,\n imports: [CommonModule, LucideDynamicIcon],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class NotificationComponent {\n /** Position of the notification stack: center, right or left top. */\n position = input<NotificationPosition>('center-top');\n\n private notificationService = inject(NotificationService);\n protected getIcon = (name: any) => getIconFromCentral(name, LucideInfo);\n\n /** Maps each notification type to its internal icon name. */\n private readonly iconMap: Record<string, string> = {\n success: 'check',\n error: 'circle-x',\n info: 'info',\n warning: 'triangle-alert',\n };\n\n /** Resolves the icon name for a notification type. */\n getNotificationIcon(type: string): string {\n return this.iconMap[type] || 'info';\n }\n\n /** Live list of active notifications. */\n notifications = this.notificationService.notifications;\n\n /** Notifications sorted with the newest first. */\n sortedNotifications = computed(\n () => [...this.notifications()].reverse(),\n );\n\n /** Removes a notification through the service. */\n removeNotification(notification: Notification): void {\n this.notificationService.removeNotification(notification);\n }\n\n /** Rounds the progress value of a notification. */\n roundProgress(progress: number | undefined): number {\n return Math.round(progress || 0);\n }\n\n /** Whether there are notifications to show. */\n hasNotifications = computed(() => this.notifications().length > 0);\n\n /** CSS classes positioning the stack according to `position`. */\n positionClass = computed(() => {\n const base = 'fixed top-4 z-[9999] space-y-4 sm:space-y-6 sm:top-6 lg:top-8';\n switch (this.position()) {\n case 'right-top':\n return `${base} right-4`;\n case 'left-top':\n return `${base} left-4`;\n default:\n return `${base} left-1/2 -translate-x-1/2`;\n }\n });\n}\n","<div [class]=\"positionClass()\">\n @for (notification of sortedNotifications(); track notification.id) {\n <div\n [ngClass]=\"{\n 'bg-green-50/80 dark:bg-green-900/30 border-green-400 dark:border-green-600 text-green-800 dark:text-green-200':\n notification.type === 'success',\n 'bg-red-50/80 dark:bg-red-900/30 border-red-400 dark:border-red-600 text-red-800 dark:text-red-200':\n notification.type === 'error',\n 'bg-blue-50/80 dark:bg-blue-900/30 border-blue-400 dark:border-blue-600 text-blue-800 dark:text-blue-200':\n notification.type === 'info',\n 'bg-yellow-50/80 dark:bg-yellow-900/30 border-yellow-400 dark:border-yellow-500 text-yellow-800 dark:text-yellow-200':\n notification.type === 'warning',\n }\"\n class=\"flex items-center w-full min-w-[320px] max-w-xs sm:max-w-sm lg:max-w-md p-4 mb-4 border-l-4 rounded-lg shadow-lg backdrop-blur-sm transition-all duration-300 transform hover:scale-105 hover:shadow-xl\"\n role=\"alert\"\n >\n <div\n [ngClass]=\"{\n 'text-green-600': notification.type === 'success',\n 'text-red-600': notification.type === 'error',\n 'text-blue-600': notification.type === 'info',\n 'text-yellow-600': notification.type === 'warning',\n }\"\n class=\"inline-flex items-center justify-center flex-shrink-0 w-10 h-10 rounded-lg bg-opacity-10\"\n >\n <svg [lucideIcon]=\"getIcon(getNotificationIcon(notification.type))\" class=\"w-6 h-6\"></svg>\n </div>\n <div class=\"ms-4 flex-1 text-sm font-medium break-words\">\n {{ notification.message }}\n </div>\n <button\n type=\"button\"\n (click)=\"removeNotification(notification)\"\n aria-label=\"Close\"\n [ngClass]=\"{\n 'text-green-600 hover:text-green-800':\n notification.type === 'success',\n 'text-red-600 hover:text-red-800': notification.type === 'error',\n 'text-blue-600 hover:text-blue-800': notification.type === 'info',\n 'text-yellow-600 hover:text-yellow-800':\n notification.type === 'warning',\n }\"\n class=\"mx-2 -my-1.5 bg-transparent focus:outline-none\"\n >\n <svg [lucideIcon]=\"getIcon('x')\" class=\"w-4 h-4\"></svg>\n </button>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["getIconFromCentral"],"mappings":"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"}