@tekus/design-system 5.34.0 → 5.36.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.
- package/fesm2022/tekus-design-system-components-action-group.mjs +1 -1
- package/fesm2022/tekus-design-system-components-action-group.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-button.mjs +24 -3
- package/fesm2022/tekus-design-system-components-button.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-card.mjs +1 -1
- package/fesm2022/tekus-design-system-components-card.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-carousel.mjs +234 -0
- package/fesm2022/tekus-design-system-components-carousel.mjs.map +1 -0
- package/fesm2022/tekus-design-system-components-color-picker.mjs +1 -1
- package/fesm2022/tekus-design-system-components-color-picker.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-drawer.mjs +1 -1
- package/fesm2022/tekus-design-system-components-drawer.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-dropdown.mjs +1 -1
- package/fesm2022/tekus-design-system-components-dropdown.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-fallback-view.mjs +1 -1
- package/fesm2022/tekus-design-system-components-fallback-view.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-header.mjs +29 -0
- package/fesm2022/tekus-design-system-components-header.mjs.map +1 -0
- package/fesm2022/tekus-design-system-components-icon.mjs +2 -2
- package/fesm2022/tekus-design-system-components-icon.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-modal.mjs +51 -31
- package/fesm2022/tekus-design-system-components-modal.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-process-steps.mjs +132 -0
- package/fesm2022/tekus-design-system-components-process-steps.mjs.map +1 -0
- package/fesm2022/tekus-design-system-components-sidebar-layout.mjs +20 -6
- package/fesm2022/tekus-design-system-components-sidebar-layout.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-stepper.mjs +1 -1
- package/fesm2022/tekus-design-system-components-stepper.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-table.mjs +1 -1
- package/fesm2022/tekus-design-system-components-table.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-toast.mjs +1 -1
- package/fesm2022/tekus-design-system-components-toast.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-toolbar.mjs +1 -1
- package/fesm2022/tekus-design-system-components-toolbar.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-topbar.mjs +1 -1
- package/fesm2022/tekus-design-system-components-topbar.mjs.map +1 -1
- package/fesm2022/tekus-design-system-components-uploader.mjs +1256 -0
- package/fesm2022/tekus-design-system-components-uploader.mjs.map +1 -0
- package/package.json +17 -1
- package/types/tekus-design-system-components-button.d.ts +20 -1
- package/types/tekus-design-system-components-carousel.d.ts +200 -0
- package/types/tekus-design-system-components-header.d.ts +33 -0
- package/types/tekus-design-system-components-modal.d.ts +31 -13
- package/types/tekus-design-system-components-process-steps.d.ts +72 -0
- package/types/tekus-design-system-components-sidebar-layout.d.ts +11 -1
- package/types/tekus-design-system-components-uploader.d.ts +524 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ElementRef, Injector, viewChild, ViewContainerRef, input, model, computed, output, effect, untracked,
|
|
2
|
+
import { inject, ElementRef, Injector, viewChild, ViewContainerRef, input, model, computed, output, afterEveryRender, effect, untracked, ChangeDetectionStrategy, Component, ApplicationRef, createComponent, Injectable } from '@angular/core';
|
|
3
3
|
import { ButtonComponent } from '@tekus/design-system/components/button';
|
|
4
4
|
import * as i1 from 'primeng/dialog';
|
|
5
5
|
import { DialogModule } from 'primeng/dialog';
|
|
@@ -16,9 +16,6 @@ import * as i2 from 'primeng/api';
|
|
|
16
16
|
*/
|
|
17
17
|
class ModalComponent {
|
|
18
18
|
constructor() {
|
|
19
|
-
/**
|
|
20
|
-
* @summary Orchestrates the reactive dynamic lifecycle.
|
|
21
|
-
*/
|
|
22
19
|
this.elementRef = inject(ElementRef);
|
|
23
20
|
this.injector = inject(Injector);
|
|
24
21
|
this.contentHost = viewChild('contentHost', { ...(ngDevMode ? { debugName: "contentHost" } : /* istanbul ignore next */ {}), read: ViewContainerRef });
|
|
@@ -70,10 +67,19 @@ class ModalComponent {
|
|
|
70
67
|
case 'full':
|
|
71
68
|
return '98vw';
|
|
72
69
|
default:
|
|
73
|
-
return '
|
|
70
|
+
return '28.125rem';
|
|
74
71
|
}
|
|
75
72
|
}, ...(ngDevMode ? [{ debugName: "modalMaxWidth" }] : /* istanbul ignore next */ []));
|
|
76
73
|
this.wasOpened = false;
|
|
74
|
+
this.registerContentLifecycleEffect();
|
|
75
|
+
this.registerDataSyncEffect();
|
|
76
|
+
afterEveryRender(() => this.checkScroll());
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* @summary Orchestrates the reactive dynamic lifecycle.
|
|
80
|
+
* @private
|
|
81
|
+
*/
|
|
82
|
+
registerContentLifecycleEffect() {
|
|
77
83
|
effect(() => {
|
|
78
84
|
const opened = this.isOpened();
|
|
79
85
|
const host = this.contentHost();
|
|
@@ -87,13 +93,15 @@ class ModalComponent {
|
|
|
87
93
|
}
|
|
88
94
|
});
|
|
89
95
|
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* @private
|
|
99
|
+
*/
|
|
100
|
+
registerDataSyncEffect() {
|
|
90
101
|
effect(() => {
|
|
91
102
|
const currentData = this.data();
|
|
92
103
|
untracked(() => this.syncDynamicInputs(currentData));
|
|
93
104
|
});
|
|
94
|
-
afterEveryRender(() => {
|
|
95
|
-
this.checkScroll();
|
|
96
|
-
});
|
|
97
105
|
}
|
|
98
106
|
ngOnDestroy() {
|
|
99
107
|
this.detachDynamicContent();
|
|
@@ -105,25 +113,32 @@ class ModalComponent {
|
|
|
105
113
|
attachDynamicContent() {
|
|
106
114
|
const type = this.content();
|
|
107
115
|
const host = this.contentHost();
|
|
108
|
-
if (!type || typeof type === 'string' || !host)
|
|
116
|
+
if (!type || typeof type === 'string' || !host) {
|
|
109
117
|
return;
|
|
118
|
+
}
|
|
110
119
|
this.detachDynamicContent();
|
|
111
|
-
const customInjector = Injector.create({
|
|
112
|
-
providers: [{ provide: TkDialogRef, useValue: this.dialogRef() }],
|
|
113
|
-
parent: this.injector,
|
|
114
|
-
});
|
|
115
120
|
this.componentRef = host.createComponent(type, {
|
|
116
|
-
injector:
|
|
121
|
+
injector: this.createContentInjector(),
|
|
117
122
|
});
|
|
118
123
|
this.syncDynamicInputs(this.data());
|
|
119
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* @private
|
|
127
|
+
*/
|
|
128
|
+
createContentInjector() {
|
|
129
|
+
return Injector.create({
|
|
130
|
+
providers: [{ provide: TkDialogRef, useValue: this.dialogRef() }],
|
|
131
|
+
parent: this.injector,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
120
134
|
/**
|
|
121
135
|
* @summary Synchronizes incoming data record with the dynamic instance @Inputs.
|
|
122
136
|
* @private
|
|
123
137
|
*/
|
|
124
138
|
syncDynamicInputs(data) {
|
|
125
|
-
if (!this.componentRef)
|
|
139
|
+
if (!this.componentRef) {
|
|
126
140
|
return;
|
|
141
|
+
}
|
|
127
142
|
Object.entries(data).forEach(([key, value]) => {
|
|
128
143
|
this.componentRef?.setInput(key, value);
|
|
129
144
|
});
|
|
@@ -169,21 +184,25 @@ class ModalComponent {
|
|
|
169
184
|
instance?.onBlockedClose?.();
|
|
170
185
|
return;
|
|
171
186
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
187
|
+
this.resolveInterceptorAndClose(instance, returnValue, hasReturnValue);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* @summary Evaluates the optional close interceptor, then executes closure.
|
|
192
|
+
* @private
|
|
193
|
+
*/
|
|
194
|
+
resolveInterceptorAndClose(instance, returnValue, hasReturnValue) {
|
|
195
|
+
const configInterceptor = this.interceptor();
|
|
196
|
+
if (!configInterceptor) {
|
|
197
|
+
this.executeClosure(returnValue, hasReturnValue);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
this.evaluateCanClose(configInterceptor(), (canCloseInterceptor) => {
|
|
201
|
+
if (!canCloseInterceptor) {
|
|
202
|
+
instance?.onBlockedClose?.();
|
|
203
|
+
return;
|
|
186
204
|
}
|
|
205
|
+
this.executeClosure(returnValue, hasReturnValue);
|
|
187
206
|
});
|
|
188
207
|
}
|
|
189
208
|
/**
|
|
@@ -248,8 +267,9 @@ class ModalComponent {
|
|
|
248
267
|
* @summary Handles actions triggered by footer buttons.
|
|
249
268
|
*/
|
|
250
269
|
handleAction(action, returnValue, preventClose = false) {
|
|
251
|
-
if (action)
|
|
270
|
+
if (action) {
|
|
252
271
|
action();
|
|
272
|
+
}
|
|
253
273
|
if (!preventClose) {
|
|
254
274
|
this.tryClose(returnValue);
|
|
255
275
|
}
|
|
@@ -270,7 +290,7 @@ class ModalComponent {
|
|
|
270
290
|
this.returnValueOnClose = null;
|
|
271
291
|
}
|
|
272
292
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ModalComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
273
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ModalComponent, isStandalone: true, selector: "tk-modal", inputs: { dialogRef: { classPropertyName: "dialogRef", publicName: "dialogRef", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, footerButtons: { classPropertyName: "footerButtons", publicName: "footerButtons", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, closeOnOutsideClick: { classPropertyName: "closeOnOutsideClick", publicName: "closeOnOutsideClick", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, interceptor: { classPropertyName: "interceptor", publicName: "interceptor", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, isOpened: { classPropertyName: "isOpened", publicName: "isOpened", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { footerButtons: "footerButtonsChange", isOpened: "isOpenedChange", closed: "closed" }, viewQueries: [{ propertyName: "contentHost", first: true, predicate: ["contentHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n [styleClass]=\"hasFooter() ? 'tk-modal--has-footer' : 'tk-modal--no-footer'\"\n class=\"tk-modal\">\n @if (title()) {\n <ng-template pTemplate=\"header\">\n <span class=\"p-dialog-title\">{{ title() }}</span>\n </ng-template>\n }\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n <ng-template pTemplate=\"footer\">\n @if (hasFooter()) {\n <section\n class=\"tk-modal__footer\"\n [class.tk-modal__footer--with-content]=\"hasScroll\">\n @for (btn of footerButtons()!; track $index) {\n <tk-button\n [label]=\"resolveProperty(btn.label)!\"\n [severity]=\"btn.severity\"\n [variant]=\"btn.variant\"\n [disabled]=\"resolveProperty(btn.disabled) ?? false\"\n (clicked)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\"\n (keydown.enter)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\"\n (keydown.space)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\" />\n }\n </section>\n }\n </ng-template>\n</p-dialog>\n", styles: [":host ::ng-deep .p-dialog{max-height:90vh;display:flex;flex-direction:column}:host ::ng-deep .p-dialog.tk-modal--no-footer .p-dialog-footer{display:none!important}:host ::ng-deep .p-dialog-content{overflow-y:auto}:host ::ng-deep .p-dialog-content .modal-container{max-height:none!important}:host ::ng-deep .p-dialog-content .modal-container .modal-header,:host ::ng-deep .p-dialog-content .modal-container>div:last-child{display:none!important}:host ::ng-deep .p-dialog-content .modal-container .overflow-auto{overflow:visible!important;max-height:none!important;margin:0!important}:host ::ng-deep .p-dialog-content .modal-container .ark-modal-body{max-height:none!important;padding-bottom:0!important}:host ::ng-deep .p-dialog-title{color:var(--tk-color-text-default, #212121)}:host ::ng-deep .p-dialog-close-button{color:var(--tk-surface-500, #8a8a8b)}:host ::ng-deep .p-dialog-close-button:hover{background:var(--tk-color-base-surface-100, #f0f0f0)!important;color:var(--tk-surface-500, #8a8a8b)}.tk-modal__content{padding-bottom:var(--tk-spacing-padding-l, 1.25rem);color:var(--tk-surface-1000, #000000)}.tk-modal__footer{display:flex;flex-direction:row;justify-content:end;align-items:center;gap:var(--tk-spacing-base-50, .5rem);padding-top:var(--tk-spacing-padding-m, 1rem)}.tk-modal__footer--with-content{padding-right:var(--tk-spacing-padding-l, 1.25rem)}\n"], dependencies: [{ kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: ButtonComponent, selector: "tk-button", inputs: ["label", "disabled", "type", "severity", "variant", "link", "icon", "iconPosition", "tooltipText", "size"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
293
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ModalComponent, isStandalone: true, selector: "tk-modal", inputs: { dialogRef: { classPropertyName: "dialogRef", publicName: "dialogRef", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, content: { classPropertyName: "content", publicName: "content", isSignal: true, isRequired: false, transformFunction: null }, footerButtons: { classPropertyName: "footerButtons", publicName: "footerButtons", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, closable: { classPropertyName: "closable", publicName: "closable", isSignal: true, isRequired: false, transformFunction: null }, closeOnOutsideClick: { classPropertyName: "closeOnOutsideClick", publicName: "closeOnOutsideClick", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, interceptor: { classPropertyName: "interceptor", publicName: "interceptor", isSignal: true, isRequired: false, transformFunction: null }, responsive: { classPropertyName: "responsive", publicName: "responsive", isSignal: true, isRequired: false, transformFunction: null }, isOpened: { classPropertyName: "isOpened", publicName: "isOpened", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { footerButtons: "footerButtonsChange", isOpened: "isOpenedChange", closed: "closed" }, viewQueries: [{ propertyName: "contentHost", first: true, predicate: ["contentHost"], descendants: true, read: ViewContainerRef, isSignal: true }], ngImport: i0, template: "<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n [styleClass]=\"hasFooter() ? 'tk-modal--has-footer' : 'tk-modal--no-footer'\"\n class=\"tk-modal\">\n @if (title()) {\n <ng-template pTemplate=\"header\">\n <span class=\"p-dialog-title\">{{ title() }}</span>\n </ng-template>\n }\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n <ng-template pTemplate=\"footer\">\n @if (hasFooter()) {\n <section\n class=\"tk-modal__footer\"\n [class.tk-modal__footer--with-content]=\"hasScroll\">\n @for (btn of footerButtons()!; track $index) {\n <tk-button\n [label]=\"resolveProperty(btn.label)!\"\n [severity]=\"btn.severity\"\n [variant]=\"btn.variant\"\n [disabled]=\"resolveProperty(btn.disabled) ?? false\"\n (clicked)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\"\n (keydown.enter)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\"\n (keydown.space)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\" />\n }\n </section>\n }\n </ng-template>\n</p-dialog>\n", styles: [":host ::ng-deep .p-dialog{max-height:90vh;display:flex;flex-direction:column}:host ::ng-deep .p-dialog.tk-modal--no-footer .p-dialog-footer{display:none!important}:host ::ng-deep .p-dialog-content{overflow-y:auto}:host ::ng-deep .p-dialog-content .modal-container{max-height:none!important}:host ::ng-deep .p-dialog-content .modal-container .modal-header,:host ::ng-deep .p-dialog-content .modal-container>div:last-child{display:none!important}:host ::ng-deep .p-dialog-content .modal-container .overflow-auto{overflow:visible!important;max-height:none!important;margin:0!important}:host ::ng-deep .p-dialog-content .modal-container .ark-modal-body{max-height:none!important;padding-bottom:0!important}:host ::ng-deep .p-dialog-title{color:var(--tk-color-text-default, #212121)}:host ::ng-deep .p-dialog-close-button{color:var(--tk-surface-500, #8a8a8b)}:host ::ng-deep .p-dialog-close-button:hover{background:var(--tk-color-base-surface-100, #f0f0f0)!important;color:var(--tk-surface-500, #8a8a8b)}.tk-modal__content{padding-bottom:var(--tk-spacing-padding-l, 1.25rem);color:var(--tk-surface-1000, #000000)}.tk-modal__footer{display:flex;flex-direction:row;justify-content:end;align-items:center;gap:var(--tk-spacing-base-50, .5rem);padding-top:var(--tk-spacing-padding-m, 1rem)}.tk-modal__footer--with-content{padding-right:var(--tk-spacing-padding-l, 1.25rem)}\n"], dependencies: [{ kind: "ngmodule", type: DialogModule }, { kind: "component", type: i1.Dialog, selector: "p-dialog", inputs: ["hostName", "header", "draggable", "resizable", "contentStyle", "contentStyleClass", "modal", "closeOnEscape", "dismissableMask", "rtl", "closable", "breakpoints", "styleClass", "maskStyleClass", "maskStyle", "showHeader", "blockScroll", "autoZIndex", "baseZIndex", "minX", "minY", "focusOnShow", "maximizable", "keepInViewport", "focusTrap", "transitionOptions", "maskMotionOptions", "motionOptions", "closeIcon", "closeAriaLabel", "closeTabindex", "minimizeIcon", "maximizeIcon", "closeButtonProps", "maximizeButtonProps", "visible", "style", "position", "role", "appendTo", "content", "contentTemplate", "footerTemplate", "closeIconTemplate", "maximizeIconTemplate", "minimizeIconTemplate", "headlessTemplate"], outputs: ["onShow", "onHide", "visibleChange", "onResizeInit", "onResizeEnd", "onDragEnd", "onMaximize"] }, { kind: "directive", type: i2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: ButtonComponent, selector: "tk-button", inputs: ["label", "disabled", "type", "severity", "variant", "link", "icon", "iconPosition", "tooltipText", "full", "ariaLabel", "size"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
274
294
|
}
|
|
275
295
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ModalComponent, decorators: [{
|
|
276
296
|
type: Component,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tekus-design-system-components-modal.mjs","sources":["../../../projects/design-system/components/modal/src/modal.component.ts","../../../projects/design-system/components/modal/src/modal.component.html","../../../projects/design-system/components/modal/src/services/modal.service.ts","../../../projects/design-system/components/modal/tekus-design-system-components-modal.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n Type,\n ElementRef,\n model,\n viewChild,\n ViewContainerRef,\n ComponentRef,\n effect,\n OnDestroy,\n untracked,\n afterEveryRender,\n inject,\n Injector,\n} from '@angular/core';\nimport { ButtonComponent } from '@tekus/design-system/components/button';\nimport { DialogModule } from 'primeng/dialog';\nimport { ModalFooterButton, ModalSizeType } from './modal.types';\nimport {\n TkCanClose,\n TkCloseInterceptor,\n TkDialogRef,\n} from '@tekus/design-system/core/types';\nimport { Observable, isObservable } from 'rxjs';\nimport { take } from 'rxjs/operators';\n\n/**\n * @component ModalComponent\n * @description\n * A programmatically controlled modal dialog used for displaying dynamic content.\n * Modernized for Angular 19 with 100% synchronous Signal-based closing interception.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-modal',\n imports: [DialogModule, ButtonComponent],\n templateUrl: './modal.component.html',\n styleUrl: './modal.component.scss',\n})\nexport class ModalComponent<T = unknown> implements OnDestroy {\n private readonly elementRef = inject(ElementRef);\n private readonly injector = inject(Injector);\n\n private readonly contentHost = viewChild('contentHost', {\n read: ViewContainerRef,\n });\n private componentRef?: ComponentRef<T>;\n\n /** The dialog ref associated with this modal */\n dialogRef = input<TkDialogRef<ModalComponent<T>, unknown> | null>(null);\n\n /** The title displayed at the top of the modal */\n title = input<string>('');\n\n /** The main content of the modal. Can be a string or a Component Type. */\n content = input<string | Type<T> | null>(null);\n\n /** Array of footer buttons with label, callback, and return value */\n footerButtons = model<ModalFooterButton[]>([]);\n\n /** Modal size: 'small', 'large', 'medium' or 'full' */\n size = input<ModalSizeType>('small');\n\n /** Whether the modal can be closed by the user via close button */\n closable = input<boolean>(true);\n\n /** Whether clicking outside the modal mask closes the modal */\n closeOnOutsideClick = input<boolean>(false);\n\n /**\n * Optional data to be passed as inputs to the dynamic component.\n */\n data = input<Partial<T>>({});\n\n /**\n * Optional interceptor called before the modal closes.\n * MUST be synchronous. Returns true to allow closing.\n */\n interceptor = input<TkCloseInterceptor | undefined>(undefined);\n\n /** Computed: whether the content is a simple string */\n isContentString = computed(() => typeof this.content() === 'string');\n\n /** Computed: whether the modal has footer buttons to display */\n hasFooter = computed(() => (this.footerButtons() ?? []).length > 0);\n\n /** Whether the modal should be responsive on mobile screens */\n responsive = input<boolean>(true);\n\n /** Visibility flag as Model Signal (allows two-way binding) */\n isOpened = model<boolean>(false);\n\n /** Whether the modal content has a scrollbar */\n hasScroll = false;\n\n // --- Internals ---\n /** Emits when the modal closes, passing the return value from footer buttons or null */\n readonly closed = output<unknown>();\n private alreadyEmitted = false;\n private returnValueOnClose: unknown = null;\n\n constructor() {\n /**\n * @summary Orchestrates the reactive dynamic lifecycle.\n */\n\n effect(() => {\n const opened = this.isOpened();\n const host = this.contentHost();\n this.dialogRef(); // Track it to re-run if it's set later\n\n untracked(() => {\n if (opened && host) {\n this.attachDynamicContent();\n } else if (!opened) {\n this.detachDynamicContent();\n }\n });\n });\n\n effect(() => {\n const currentData = this.data();\n untracked(() => this.syncDynamicInputs(currentData));\n });\n\n afterEveryRender(() => {\n this.checkScroll();\n });\n }\n\n /** Computed: calculates modal max-width based on `size` */\n modalMaxWidth = computed(() => {\n switch (this.size()) {\n case 'large':\n return '67.5rem';\n case 'medium':\n return '35rem';\n case 'full':\n return '98vw';\n default:\n return '25rem';\n }\n });\n\n ngOnDestroy(): void {\n this.detachDynamicContent();\n }\n\n /**\n * @summary Orchestrates dynamic rendering and destruction based on visibility.\n * @private\n */\n private attachDynamicContent(): void {\n const type = this.content();\n const host = this.contentHost();\n\n if (!type || typeof type === 'string' || !host) return;\n this.detachDynamicContent();\n\n const customInjector = Injector.create({\n providers: [{ provide: TkDialogRef, useValue: this.dialogRef() }],\n parent: this.injector,\n });\n\n this.componentRef = host.createComponent(type, {\n injector: customInjector,\n });\n this.syncDynamicInputs(this.data());\n }\n\n /**\n * @summary Synchronizes incoming data record with the dynamic instance @Inputs.\n * @private\n */\n private syncDynamicInputs(data: Partial<T>): void {\n if (!this.componentRef) return;\n Object.entries(data).forEach(([key, value]) => {\n this.componentRef?.setInput(key, value);\n });\n }\n\n /**\n * @summary Safely destroys the dynamic component and clears references.\n * @private\n */\n private detachDynamicContent(): void {\n if (this.componentRef) {\n this.componentRef.destroy();\n this.componentRef = undefined;\n }\n }\n\n /**\n * Checks if the modal content has a scrollbar and updates `hasScroll` state.\n */\n checkScroll(): void {\n const contentEl =\n this.elementRef.nativeElement.querySelector('.p-dialog-content');\n if (contentEl) {\n this.hasScroll = contentEl.scrollHeight > contentEl.clientHeight;\n }\n }\n\n private wasOpened = false;\n\n /**\n * Opens the modal dialog.\n */\n open(): void {\n this.wasOpened = true;\n this.isOpened.set(true);\n this.resetClosureState();\n }\n\n /**\n * @summary Main entry point for closure requests.\n * Supports synchronous and asynchronous (Promise/Observable) evaluations.\n * @param returnValue (Optional) Value to emit on close.\n */\n tryClose(returnValue: unknown = null): void {\n const hasReturnValue = arguments.length > 0;\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n const canCloseFn = instance?.canClose ? instance.canClose() : true;\n\n this.evaluateCanClose(canCloseFn, (canCloseInstance) => {\n if (!canCloseInstance) {\n instance?.onBlockedClose?.();\n return;\n }\n\n const configInterceptor = this.interceptor();\n if (configInterceptor) {\n const interceptorResult = configInterceptor();\n this.evaluateCanClose(interceptorResult, (canCloseInterceptor) => {\n if (canCloseInterceptor) {\n this.executeClosure(returnValue, hasReturnValue);\n } else {\n instance?.onBlockedClose?.();\n }\n });\n } else {\n this.executeClosure(returnValue, hasReturnValue);\n }\n });\n }\n\n /**\n * Evaluates a boolean, Promise or Observable to check if closing is allowed.\n */\n private evaluateCanClose(\n result: boolean | Promise<boolean> | Observable<boolean>,\n callback: (canClose: boolean) => void\n ): void {\n if (isObservable(result)) {\n result.pipe(take(1)).subscribe({\n next: (res) => callback(res),\n error: () => callback(false),\n });\n } else if (result instanceof Promise) {\n result.then(\n (res) => callback(res),\n () => callback(false)\n );\n } else {\n callback(result);\n }\n }\n\n /**\n * Resolves a static or functional property of a button.\n */\n resolveProperty<R>(prop: R | (() => R) | undefined): R | undefined {\n if (typeof prop === 'function') {\n return (prop as () => R)();\n }\n return prop;\n }\n\n /**\n * @summary Unified logic to execute the final closure state change.\n * @private\n */\n private executeClosure(returnValue: unknown, hasReturnValue: boolean): void {\n if (hasReturnValue) {\n this.alreadyEmitted = true;\n this.returnValueOnClose = returnValue;\n }\n this.isOpened.set(false);\n }\n\n /**\n * @summary Handles external visibility changes (from p-dialog 'X' or Escape).\n * Ensures the reactive guard is respected before allowing closure.\n */\n onVisibleChange(visible: boolean): void {\n if (!visible) {\n this.tryClose();\n }\n }\n\n /**\n * Handles the close event from the underlying dialog component.\n */\n handleClose(): void {\n if (!this.wasOpened || this.isOpened()) {\n return;\n }\n const valueToEmit = this.alreadyEmitted ? this.returnValueOnClose : null;\n this.closed.emit(valueToEmit);\n this.resetClosureState();\n this.wasOpened = false;\n }\n\n /**\n * @summary Handles actions triggered by footer buttons.\n */\n handleAction(\n action: (() => void) | undefined,\n returnValue: unknown,\n preventClose = false\n ): void {\n if (action) action();\n if (!preventClose) {\n this.tryClose(returnValue);\n }\n }\n\n /**\n * @summary Safely closes the modal, optionally passing a return value.\n * @param returnValue Value to emit when closing.\n */\n close(returnValue: unknown = null): void {\n this.tryClose(returnValue);\n }\n\n /**\n * @private\n * Encapsulates state cleanup to avoid repetitive assignments\n */\n private resetClosureState(): void {\n this.alreadyEmitted = false;\n this.returnValueOnClose = null;\n }\n}\n","<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n [styleClass]=\"hasFooter() ? 'tk-modal--has-footer' : 'tk-modal--no-footer'\"\n class=\"tk-modal\">\n @if (title()) {\n <ng-template pTemplate=\"header\">\n <span class=\"p-dialog-title\">{{ title() }}</span>\n </ng-template>\n }\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n <ng-template pTemplate=\"footer\">\n @if (hasFooter()) {\n <section\n class=\"tk-modal__footer\"\n [class.tk-modal__footer--with-content]=\"hasScroll\">\n @for (btn of footerButtons()!; track $index) {\n <tk-button\n [label]=\"resolveProperty(btn.label)!\"\n [severity]=\"btn.severity\"\n [variant]=\"btn.variant\"\n [disabled]=\"resolveProperty(btn.disabled) ?? false\"\n (clicked)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\"\n (keydown.enter)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\"\n (keydown.space)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\" />\n }\n </section>\n }\n </ng-template>\n</p-dialog>\n","import { Injectable, ApplicationRef, ComponentRef, createComponent, EmbeddedViewRef, inject } from '@angular/core';\nimport { ModalComponent } from '../modal.component';\nimport { ModalConfig } from '../modal.types';\nimport { TkDialogRef } from '@tekus/design-system/core/types';\n\n/**\n * @service ModalService\n * @description\n * Service responsible for programmatically opening and managing modal dialogs.\n * It handles component creation, attachment to the document body, and cleanup.\n */\n@Injectable({ providedIn: 'root' })\nexport class ModalService {\n private readonly appRef = inject(ApplicationRef);\n\n /** Reference to the currently open modal dialog ref */\n private dialogRef: TkDialogRef<ModalComponent> | null = null;\n\n /** Internal getter for testing purposes */\n get modalRefForTesting(): ComponentRef<ModalComponent> | null {\n return this.dialogRef?.componentRef || null;\n }\n /** Internal setter for testing purposes */\n set modalRefForTesting(ref: ComponentRef<ModalComponent> | null) {\n this.dialogRef = ref ? new TkDialogRef(ref) : null;\n }\n\n /**\n * Opens a modal dialog with the provided configuration.\n * Only one modal can be open at a time.\n * @param config Configuration object for the modal (title, content, buttons, etc.)\n * @returns A TkDialogRef for the opened modal.\n */\n open<T = unknown, R = unknown>(config: ModalConfig): TkDialogRef<ModalComponent<T>, R> {\n if (this.dialogRef) {\n return this.dialogRef as unknown as TkDialogRef<ModalComponent<T>, R>;\n }\n\n const componentRef = createComponent(ModalComponent, {\n environmentInjector: this.appRef.injector,\n }) as ComponentRef<ModalComponent<T>>;\n\n this.appRef.attachView(componentRef.hostView);\n\n const domElem = (componentRef.hostView as EmbeddedViewRef<unknown>).rootNodes[0] as HTMLElement;\n document.body.appendChild(domElem);\n\n const dialogRef = new TkDialogRef<ModalComponent<T>, R>(componentRef);\n this.dialogRef = dialogRef as unknown as TkDialogRef<ModalComponent>;\n\n componentRef.setInput('title', config.title);\n componentRef.setInput('content', config.content);\n componentRef.setInput('footerButtons', config.footerButtons || []);\n componentRef.setInput('size', config.size || 'small');\n componentRef.setInput('closable', config.closable ?? true);\n componentRef.setInput('closeOnOutsideClick', config.closeOnOutsideClick ?? false);\n componentRef.setInput('interceptor', config.interceptor);\n componentRef.setInput('data', config.data || {});\n componentRef.setInput('dialogRef', dialogRef);\n\n componentRef.instance.closed.subscribe((value: unknown) => {\n dialogRef.emitClose(value as R);\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n this.dialogRef = null;\n });\n\n componentRef.instance.open();\n\n return dialogRef;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tekus-design-system-components-modal.mjs","sources":["../../../projects/design-system/components/modal/src/modal.component.ts","../../../projects/design-system/components/modal/src/modal.component.html","../../../projects/design-system/components/modal/src/services/modal.service.ts","../../../projects/design-system/components/modal/tekus-design-system-components-modal.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n output,\n Type,\n ElementRef,\n model,\n viewChild,\n ViewContainerRef,\n ComponentRef,\n effect,\n OnDestroy,\n untracked,\n afterEveryRender,\n inject,\n Injector,\n} from '@angular/core';\nimport { ButtonComponent } from '@tekus/design-system/components/button';\nimport { DialogModule } from 'primeng/dialog';\nimport { ModalFooterButton, ModalSizeType } from './modal.types';\nimport {\n TkCanClose,\n TkCloseInterceptor,\n TkDialogRef,\n} from '@tekus/design-system/core/types';\nimport { Observable, isObservable } from 'rxjs';\nimport { take } from 'rxjs/operators';\n\n/**\n * @component ModalComponent\n * @description\n * A programmatically controlled modal dialog used for displaying dynamic content.\n * Modernized for Angular 19 with 100% synchronous Signal-based closing interception.\n */\n@Component({\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'tk-modal',\n imports: [DialogModule, ButtonComponent],\n templateUrl: './modal.component.html',\n styleUrl: './modal.component.scss',\n})\nexport class ModalComponent<T = unknown> implements OnDestroy {\n private readonly elementRef = inject(ElementRef);\n private readonly injector = inject(Injector);\n\n private readonly contentHost = viewChild('contentHost', {\n read: ViewContainerRef,\n });\n private componentRef?: ComponentRef<T>;\n\n /** The dialog ref associated with this modal */\n readonly dialogRef = input<TkDialogRef<ModalComponent<T>, unknown> | null>(null);\n\n /** The title displayed at the top of the modal */\n readonly title = input<string>('');\n\n /** The main content of the modal. Can be a string or a Component Type. */\n readonly content = input<string | Type<T> | null>(null);\n\n /** Array of footer buttons with label, callback, and return value */\n readonly footerButtons = model<ModalFooterButton[]>([]);\n\n /** Modal size: 'small', 'large', 'medium' or 'full' */\n readonly size = input<ModalSizeType>('small');\n\n /** Whether the modal can be closed by the user via close button */\n readonly closable = input<boolean>(true);\n\n /** Whether clicking outside the modal mask closes the modal */\n readonly closeOnOutsideClick = input<boolean>(false);\n\n /**\n * Optional data to be passed as inputs to the dynamic component.\n */\n data = input<Partial<T>>({});\n\n /**\n * Optional interceptor called before the modal closes.\n * MUST be synchronous. Returns true to allow closing.\n */\n readonly interceptor = input<TkCloseInterceptor | undefined>(undefined);\n\n /** Computed: whether the content is a simple string */\n readonly isContentString = computed(() => typeof this.content() === 'string');\n\n /** Computed: whether the modal has footer buttons to display */\n readonly hasFooter = computed(() => (this.footerButtons() ?? []).length > 0);\n\n /** Whether the modal should be responsive on mobile screens */\n readonly responsive = input<boolean>(true);\n\n /** Visibility flag as Model Signal (allows two-way binding) */\n readonly isOpened = model<boolean>(false);\n\n /** Whether the modal content has a scrollbar */\n hasScroll = false;\n\n // --- Internals ---\n /** Emits when the modal closes, passing the return value from footer buttons or null */\n readonly closed = output<unknown>();\n private alreadyEmitted = false;\n private returnValueOnClose: unknown = null;\n\n constructor() {\n this.registerContentLifecycleEffect();\n this.registerDataSyncEffect();\n afterEveryRender(() => this.checkScroll());\n }\n\n /**\n * @summary Orchestrates the reactive dynamic lifecycle.\n * @private\n */\n private registerContentLifecycleEffect(): void {\n effect(() => {\n const opened = this.isOpened();\n const host = this.contentHost();\n this.dialogRef(); // Track it to re-run if it's set later\n\n untracked(() => {\n if (opened && host) {\n this.attachDynamicContent();\n } else if (!opened) {\n this.detachDynamicContent();\n }\n });\n });\n }\n\n /**\n * @private\n */\n private registerDataSyncEffect(): void {\n effect(() => {\n const currentData = this.data();\n untracked(() => this.syncDynamicInputs(currentData));\n });\n }\n\n /** Computed: calculates modal max-width based on `size` */\n modalMaxWidth = computed(() => {\n switch (this.size()) {\n case 'large':\n return '67.5rem';\n case 'medium':\n return '35rem';\n case 'full':\n return '98vw';\n default:\n return '28.125rem';\n }\n });\n\n ngOnDestroy(): void {\n this.detachDynamicContent();\n }\n\n /**\n * @summary Orchestrates dynamic rendering and destruction based on visibility.\n * @private\n */\n private attachDynamicContent(): void {\n const type = this.content();\n const host = this.contentHost();\n\n if (!type || typeof type === 'string' || !host) {\n return;\n }\n this.detachDynamicContent();\n\n this.componentRef = host.createComponent(type, {\n injector: this.createContentInjector(),\n });\n this.syncDynamicInputs(this.data());\n }\n\n /**\n * @private\n */\n private createContentInjector(): Injector {\n return Injector.create({\n providers: [{ provide: TkDialogRef, useValue: this.dialogRef() }],\n parent: this.injector,\n });\n }\n\n /**\n * @summary Synchronizes incoming data record with the dynamic instance @Inputs.\n * @private\n */\n private syncDynamicInputs(data: Partial<T>): void {\n if (!this.componentRef) {\n return;\n }\n Object.entries(data).forEach(([key, value]) => {\n this.componentRef?.setInput(key, value);\n });\n }\n\n /**\n * @summary Safely destroys the dynamic component and clears references.\n * @private\n */\n private detachDynamicContent(): void {\n if (this.componentRef) {\n this.componentRef.destroy();\n this.componentRef = undefined;\n }\n }\n\n /**\n * Checks if the modal content has a scrollbar and updates `hasScroll` state.\n */\n checkScroll(): void {\n const contentEl =\n this.elementRef.nativeElement.querySelector('.p-dialog-content');\n if (contentEl) {\n this.hasScroll = contentEl.scrollHeight > contentEl.clientHeight;\n }\n }\n\n private wasOpened = false;\n\n /**\n * Opens the modal dialog.\n */\n open(): void {\n this.wasOpened = true;\n this.isOpened.set(true);\n this.resetClosureState();\n }\n\n /**\n * @summary Main entry point for closure requests.\n * Supports synchronous and asynchronous (Promise/Observable) evaluations.\n * @param returnValue (Optional) Value to emit on close.\n */\n tryClose(returnValue: unknown = null): void {\n const hasReturnValue = arguments.length > 0;\n const instance = this.componentRef?.instance as TkCanClose | undefined;\n const canCloseFn = instance?.canClose ? instance.canClose() : true;\n\n this.evaluateCanClose(canCloseFn, (canCloseInstance) => {\n if (!canCloseInstance) {\n instance?.onBlockedClose?.();\n return;\n }\n this.resolveInterceptorAndClose(instance, returnValue, hasReturnValue);\n });\n }\n\n /**\n * @summary Evaluates the optional close interceptor, then executes closure.\n * @private\n */\n private resolveInterceptorAndClose(\n instance: TkCanClose | undefined,\n returnValue: unknown,\n hasReturnValue: boolean\n ): void {\n const configInterceptor = this.interceptor();\n if (!configInterceptor) {\n this.executeClosure(returnValue, hasReturnValue);\n return;\n }\n\n this.evaluateCanClose(configInterceptor(), (canCloseInterceptor) => {\n if (!canCloseInterceptor) {\n instance?.onBlockedClose?.();\n return;\n }\n this.executeClosure(returnValue, hasReturnValue);\n });\n }\n\n /**\n * Evaluates a boolean, Promise or Observable to check if closing is allowed.\n */\n private evaluateCanClose(\n result: boolean | Promise<boolean> | Observable<boolean>,\n callback: (canClose: boolean) => void\n ): void {\n if (isObservable(result)) {\n result.pipe(take(1)).subscribe({\n next: (res) => callback(res),\n error: () => callback(false),\n });\n } else if (result instanceof Promise) {\n result.then(\n (res) => callback(res),\n () => callback(false)\n );\n } else {\n callback(result);\n }\n }\n\n /**\n * Resolves a static or functional property of a button.\n */\n resolveProperty<R>(prop: R | (() => R) | undefined): R | undefined {\n if (typeof prop === 'function') {\n return (prop as () => R)();\n }\n return prop;\n }\n\n /**\n * @summary Unified logic to execute the final closure state change.\n * @private\n */\n private executeClosure(returnValue: unknown, hasReturnValue: boolean): void {\n if (hasReturnValue) {\n this.alreadyEmitted = true;\n this.returnValueOnClose = returnValue;\n }\n this.isOpened.set(false);\n }\n\n /**\n * @summary Handles external visibility changes (from p-dialog 'X' or Escape).\n * Ensures the reactive guard is respected before allowing closure.\n */\n onVisibleChange(visible: boolean): void {\n if (!visible) {\n this.tryClose();\n }\n }\n\n /**\n * Handles the close event from the underlying dialog component.\n */\n handleClose(): void {\n if (!this.wasOpened || this.isOpened()) {\n return;\n }\n const valueToEmit = this.alreadyEmitted ? this.returnValueOnClose : null;\n this.closed.emit(valueToEmit);\n this.resetClosureState();\n this.wasOpened = false;\n }\n\n /**\n * @summary Handles actions triggered by footer buttons.\n */\n handleAction(\n action: (() => void) | undefined,\n returnValue: unknown,\n preventClose = false\n ): void {\n if (action) {\n action();\n }\n if (!preventClose) {\n this.tryClose(returnValue);\n }\n }\n\n /**\n * @summary Safely closes the modal, optionally passing a return value.\n * @param returnValue Value to emit when closing.\n */\n close(returnValue: unknown = null): void {\n this.tryClose(returnValue);\n }\n\n /**\n * @private\n * Encapsulates state cleanup to avoid repetitive assignments\n */\n private resetClosureState(): void {\n this.alreadyEmitted = false;\n this.returnValueOnClose = null;\n }\n}\n","<p-dialog\n [modal]=\"true\"\n [visible]=\"isOpened()\"\n (visibleChange)=\"onVisibleChange($event)\"\n [closable]=\"closable()\"\n [dismissableMask]=\"closeOnOutsideClick()\"\n [draggable]=\"false\"\n [focusOnShow]=\"false\"\n [header]=\"title()\"\n [style]=\"{\n 'max-width': modalMaxWidth(),\n width: 'calc(100% - var(--tk-spacing-base-200))',\n }\"\n (onHide)=\"handleClose()\"\n (onShow)=\"checkScroll()\"\n [styleClass]=\"hasFooter() ? 'tk-modal--has-footer' : 'tk-modal--no-footer'\"\n class=\"tk-modal\">\n @if (title()) {\n <ng-template pTemplate=\"header\">\n <span class=\"p-dialog-title\">{{ title() }}</span>\n </ng-template>\n }\n <section class=\"tk-modal__content\">\n @if (content()) {\n @if (isContentString()) {\n <p [innerHTML]=\"content()\"></p>\n } @else {\n <ng-template #contentHost></ng-template>\n }\n }\n </section>\n\n <ng-template pTemplate=\"footer\">\n @if (hasFooter()) {\n <section\n class=\"tk-modal__footer\"\n [class.tk-modal__footer--with-content]=\"hasScroll\">\n @for (btn of footerButtons()!; track $index) {\n <tk-button\n [label]=\"resolveProperty(btn.label)!\"\n [severity]=\"btn.severity\"\n [variant]=\"btn.variant\"\n [disabled]=\"resolveProperty(btn.disabled) ?? false\"\n (clicked)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\"\n (keydown.enter)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\"\n (keydown.space)=\"handleAction(btn.action, btn.returnValue, btn.preventClose)\" />\n }\n </section>\n }\n </ng-template>\n</p-dialog>\n","import { Injectable, ApplicationRef, ComponentRef, createComponent, EmbeddedViewRef, inject } from '@angular/core';\nimport { ModalComponent } from '../modal.component';\nimport { ModalConfig } from '../modal.types';\nimport { TkDialogRef } from '@tekus/design-system/core/types';\n\n/**\n * @service ModalService\n * @description\n * Service responsible for programmatically opening and managing modal dialogs.\n * It handles component creation, attachment to the document body, and cleanup.\n */\n@Injectable({ providedIn: 'root' })\nexport class ModalService {\n private readonly appRef = inject(ApplicationRef);\n\n /** Reference to the currently open modal dialog ref */\n private dialogRef: TkDialogRef<ModalComponent> | null = null;\n\n /** Internal getter for testing purposes */\n get modalRefForTesting(): ComponentRef<ModalComponent> | null {\n return this.dialogRef?.componentRef || null;\n }\n /** Internal setter for testing purposes */\n set modalRefForTesting(ref: ComponentRef<ModalComponent> | null) {\n this.dialogRef = ref ? new TkDialogRef(ref) : null;\n }\n\n /**\n * Opens a modal dialog with the provided configuration.\n * Only one modal can be open at a time.\n * @param config Configuration object for the modal (title, content, buttons, etc.)\n * @returns A TkDialogRef for the opened modal.\n */\n open<T = unknown, R = unknown>(config: ModalConfig): TkDialogRef<ModalComponent<T>, R> {\n if (this.dialogRef) {\n return this.dialogRef as unknown as TkDialogRef<ModalComponent<T>, R>;\n }\n\n const componentRef = createComponent(ModalComponent, {\n environmentInjector: this.appRef.injector,\n }) as ComponentRef<ModalComponent<T>>;\n\n this.appRef.attachView(componentRef.hostView);\n\n const domElem = (componentRef.hostView as EmbeddedViewRef<unknown>).rootNodes[0] as HTMLElement;\n document.body.appendChild(domElem);\n\n const dialogRef = new TkDialogRef<ModalComponent<T>, R>(componentRef);\n this.dialogRef = dialogRef as unknown as TkDialogRef<ModalComponent>;\n\n componentRef.setInput('title', config.title);\n componentRef.setInput('content', config.content);\n componentRef.setInput('footerButtons', config.footerButtons || []);\n componentRef.setInput('size', config.size || 'small');\n componentRef.setInput('closable', config.closable ?? true);\n componentRef.setInput('closeOnOutsideClick', config.closeOnOutsideClick ?? false);\n componentRef.setInput('interceptor', config.interceptor);\n componentRef.setInput('data', config.data || {});\n componentRef.setInput('dialogRef', dialogRef);\n\n componentRef.instance.closed.subscribe((value: unknown) => {\n dialogRef.emitClose(value as R);\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n this.dialogRef = null;\n });\n\n componentRef.instance.open();\n\n return dialogRef;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, output, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { ProgressSpinner } from 'primeng/progressspinner';
|
|
4
|
+
import { IconComponent } from '@tekus/design-system/components/icon';
|
|
5
|
+
import { MessageComponent } from '@tekus/design-system/components/message';
|
|
6
|
+
|
|
7
|
+
class ProcessStepsComponent {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.steps = input([], ...(ngDevMode ? [{ debugName: "steps" }] : /* istanbul ignore next */ []));
|
|
10
|
+
this.title = input.required(...(ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []));
|
|
11
|
+
this.description = input(...(ngDevMode ? [undefined, { debugName: "description" }] : /* istanbul ignore next */ []));
|
|
12
|
+
this.icon = input('gears', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
13
|
+
this.status = input('progress', ...(ngDevMode ? [{ debugName: "status" }] : /* istanbul ignore next */ []));
|
|
14
|
+
/** Whether to show the spinner + icon header while `status` is `progress`. */
|
|
15
|
+
this.showIcon = input(true, ...(ngDevMode ? [{ debugName: "showIcon" }] : /* istanbul ignore next */ []));
|
|
16
|
+
/**
|
|
17
|
+
* Strips the panel down to just the step list: no padding, and no
|
|
18
|
+
* `title`/`description` header while `status` is `progress` — for hosts
|
|
19
|
+
* that provide their own framing (e.g. a card) and already show the file
|
|
20
|
+
* name elsewhere. The final result view (`success`/`error`/`warning`)
|
|
21
|
+
* still shows its own title/message, since that's the only place the
|
|
22
|
+
* outcome text is surfaced.
|
|
23
|
+
*/
|
|
24
|
+
this.compact = input(false, ...(ngDevMode ? [{ debugName: "compact" }] : /* istanbul ignore next */ []));
|
|
25
|
+
/** Specific problems to list inside the result message box (ignored when `status` is `success`). */
|
|
26
|
+
this.errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
|
|
27
|
+
/** Seconds until the countdown finishes; omit to disable it. */
|
|
28
|
+
this.countdownSeconds = input(...(ngDevMode ? [undefined, { debugName: "countdownSeconds" }] : /* istanbul ignore next */ []));
|
|
29
|
+
/**
|
|
30
|
+
* Countdown text; `{seconds}` is replaced with the seconds left. Defaults to a "closing"
|
|
31
|
+
* message, but the countdown isn't only for closing — override it to match what
|
|
32
|
+
* `(countdownFinished)` actually does.
|
|
33
|
+
*/
|
|
34
|
+
this.countdownLabel = input('Closing in {seconds}s…', ...(ngDevMode ? [{ debugName: "countdownLabel" }] : /* istanbul ignore next */ []));
|
|
35
|
+
/** Emitted once when the countdown reaches zero — the consumer decides what happens next (close a modal, show a toast, etc.). */
|
|
36
|
+
this.countdownFinished = output();
|
|
37
|
+
/** Seconds left in the countdown, or `undefined` while it's disabled. */
|
|
38
|
+
this.remainingSeconds = signal(undefined, ...(ngDevMode ? [{ debugName: "remainingSeconds" }] : /* istanbul ignore next */ []));
|
|
39
|
+
this.resultIcon = computed(() => {
|
|
40
|
+
switch (this.status()) {
|
|
41
|
+
case 'error':
|
|
42
|
+
return 'xmark';
|
|
43
|
+
case 'warning':
|
|
44
|
+
return 'triangle-exclamation';
|
|
45
|
+
default:
|
|
46
|
+
return 'check';
|
|
47
|
+
}
|
|
48
|
+
}, ...(ngDevMode ? [{ debugName: "resultIcon" }] : /* istanbul ignore next */ []));
|
|
49
|
+
this.resultColor = computed(() => {
|
|
50
|
+
switch (this.status()) {
|
|
51
|
+
case 'error':
|
|
52
|
+
return 'danger';
|
|
53
|
+
case 'warning':
|
|
54
|
+
return 'warning';
|
|
55
|
+
default:
|
|
56
|
+
return 'success';
|
|
57
|
+
}
|
|
58
|
+
}, ...(ngDevMode ? [{ debugName: "resultColor" }] : /* istanbul ignore next */ []));
|
|
59
|
+
/** Severity for the message box wrapping `description`/`errors` (success has no box). */
|
|
60
|
+
this.resultMessageSeverity = computed(() => this.status() === 'error' ? 'error' : 'warn', ...(ngDevMode ? [{ debugName: "resultMessageSeverity" }] : /* istanbul ignore next */ []));
|
|
61
|
+
/** Severity for the compact terminal banner (`tk-message`) — unlike `resultMessageSeverity`, success gets its own box here. */
|
|
62
|
+
this.bannerSeverity = computed(() => {
|
|
63
|
+
if (this.status() === 'error') {
|
|
64
|
+
return 'error';
|
|
65
|
+
}
|
|
66
|
+
if (this.status() === 'warning') {
|
|
67
|
+
return 'warn';
|
|
68
|
+
}
|
|
69
|
+
return 'success';
|
|
70
|
+
}, ...(ngDevMode ? [{ debugName: "bannerSeverity" }] : /* istanbul ignore next */ []));
|
|
71
|
+
/** `countdownLabel` with `{seconds}` filled in, or `undefined` while the countdown is disabled. */
|
|
72
|
+
this.countdownText = computed(() => {
|
|
73
|
+
const seconds = this.remainingSeconds();
|
|
74
|
+
if (seconds === undefined) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return this.countdownLabel().replace('{seconds}', String(seconds));
|
|
78
|
+
}, ...(ngDevMode ? [{ debugName: "countdownText" }] : /* istanbul ignore next */ []));
|
|
79
|
+
effect(onCleanup => this.runCountdown(onCleanup));
|
|
80
|
+
}
|
|
81
|
+
/** Starts (or disables) the countdown whenever `status`/`countdownSeconds` change. */
|
|
82
|
+
runCountdown(onCleanup) {
|
|
83
|
+
const total = this.countdownSeconds();
|
|
84
|
+
if (this.status() === 'progress' || !total) {
|
|
85
|
+
this.remainingSeconds.set(undefined);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
this.remainingSeconds.set(total);
|
|
89
|
+
const intervalId = setInterval(() => this.tickCountdown(intervalId), 1000);
|
|
90
|
+
onCleanup(() => clearInterval(intervalId));
|
|
91
|
+
}
|
|
92
|
+
/** Decrements `remainingSeconds` by one and emits `countdownFinished` once it bottoms out. */
|
|
93
|
+
tickCountdown(intervalId) {
|
|
94
|
+
const next = (this.remainingSeconds() ?? 1) - 1;
|
|
95
|
+
this.remainingSeconds.set(Math.max(next, 0));
|
|
96
|
+
if (next <= 0) {
|
|
97
|
+
clearInterval(intervalId);
|
|
98
|
+
this.countdownFinished.emit();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Accessible suffix announced per step since state is otherwise
|
|
103
|
+
* conveyed only through color/icon.
|
|
104
|
+
*/
|
|
105
|
+
stepStatusLabel(state) {
|
|
106
|
+
switch (state) {
|
|
107
|
+
case 'done':
|
|
108
|
+
return 'completed';
|
|
109
|
+
case 'active':
|
|
110
|
+
return 'in progress';
|
|
111
|
+
case 'error':
|
|
112
|
+
return 'failed';
|
|
113
|
+
case 'warning':
|
|
114
|
+
return 'needs attention';
|
|
115
|
+
default:
|
|
116
|
+
return 'pending';
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ProcessStepsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
120
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.17", type: ProcessStepsComponent, isStandalone: true, selector: "tk-process-steps", inputs: { steps: { classPropertyName: "steps", publicName: "steps", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: true, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: false, transformFunction: null }, showIcon: { classPropertyName: "showIcon", publicName: "showIcon", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, countdownSeconds: { classPropertyName: "countdownSeconds", publicName: "countdownSeconds", isSignal: true, isRequired: false, transformFunction: null }, countdownLabel: { classPropertyName: "countdownLabel", publicName: "countdownLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { countdownFinished: "countdownFinished" }, ngImport: i0, template: "<output class=\"tk-process-steps\" [class.tk-process-steps--compact]=\"compact()\">\n @if (status() === 'progress' && showIcon()) {\n <div class=\"tk-process-steps__spinner-wrapper\" aria-hidden=\"true\">\n <p-progressSpinner\n class=\"tk-process-steps__spinner-progress\"\n strokeWidth=\"3\"\n animationDuration=\"1s\" />\n <tk-icon\n [icon]=\"icon()\"\n styleIcon=\"fal\"\n size=\"lg\"\n class=\"tk-process-steps__spinner-icon\" />\n </div>\n }\n\n @if (status() === 'progress' && !compact()) {\n <h3 class=\"tk-process-steps__title\">{{ title() }}</h3>\n @if (description()) {\n <p class=\"tk-process-steps__description\">{{ description() }}</p>\n }\n }\n\n @if (status() === 'progress' || compact()) {\n <ul class=\"tk-process-steps__steps\">\n @for (step of steps(); track step.label) {\n <li\n class=\"tk-process-steps__step\"\n [class.tk-process-steps__step--active]=\"step.state === 'active'\"\n [class.tk-process-steps__step--done]=\"step.state === 'done'\"\n [class.tk-process-steps__step--error]=\"step.state === 'error'\"\n [class.tk-process-steps__step--warning]=\"step.state === 'warning'\"\n [attr.aria-current]=\"step.state === 'active' ? 'step' : null\">\n <span\n class=\"tk-process-steps__step-icon-wrapper\"\n [class.tk-process-steps__step-icon-wrapper--done]=\"step.state === 'done'\"\n [class.tk-process-steps__step-icon-wrapper--error]=\"step.state === 'error'\"\n [class.tk-process-steps__step-icon-wrapper--warning]=\"step.state === 'warning'\">\n @switch (step.state) {\n @case ('done') {\n <tk-icon\n icon=\"circle-check\"\n styleIcon=\"fal\"\n size=\"1x\"\n color=\"success\"\n class=\"tk-process-steps__step-icon--done\"\n aria-hidden=\"true\" />\n }\n @case ('error') {\n <tk-icon\n icon=\"circle-xmark\"\n styleIcon=\"fal\"\n size=\"1x\"\n color=\"danger\"\n class=\"tk-process-steps__step-icon--error\"\n aria-hidden=\"true\" />\n }\n @case ('warning') {\n <tk-icon\n icon=\"triangle-exclamation\"\n styleIcon=\"fal\"\n size=\"1x\"\n color=\"warning\"\n class=\"tk-process-steps__step-icon--warning\"\n aria-hidden=\"true\" />\n }\n @case ('active') {\n <span class=\"tk-process-steps__step-spinner\" aria-hidden=\"true\">\n <p-progressSpinner strokeWidth=\"5\" animationDuration=\"0.8s\" />\n </span>\n }\n @default {\n <span class=\"tk-process-steps__step-dot\" aria-hidden=\"true\"></span>\n }\n }\n </span>\n <span class=\"tk-process-steps__step-content\">\n <span class=\"tk-process-steps__step-label\">\n {{ step.label }}\n <span class=\"tk-process-steps__sr-only\">({{ stepStatusLabel(step.state) }})</span>\n </span>\n @if (step.description) {\n <span class=\"tk-process-steps__step-description\">{{ step.description }}</span>\n }\n </span>\n </li>\n }\n </ul>\n }\n\n @if (status() !== 'progress') {\n @if (compact()) {\n @if (errors().length || description()) {\n <tk-message [severity]=\"bannerSeverity()\" class=\"tk-process-steps__banner\">\n @if (errors().length) {\n <ul class=\"tk-process-steps__result-errors\">\n @for (error of errors(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n } @else {\n {{ description() }}\n }\n </tk-message>\n }\n } @else {\n <div\n class=\"tk-process-steps__result-circle\"\n [class.tk-process-steps__result-circle--success]=\"status() === 'success'\"\n [class.tk-process-steps__result-circle--error]=\"status() === 'error'\"\n [class.tk-process-steps__result-circle--warning]=\"status() === 'warning'\">\n <tk-icon\n [icon]=\"resultIcon()\"\n styleIcon=\"fal\"\n size=\"2x\"\n [color]=\"resultColor()\"\n aria-hidden=\"true\" />\n </div>\n <h3\n class=\"tk-process-steps__result-title\"\n [class.tk-process-steps__result-title--success]=\"status() === 'success'\"\n [class.tk-process-steps__result-title--error]=\"status() === 'error'\"\n [class.tk-process-steps__result-title--warning]=\"status() === 'warning'\">\n {{ title() }}\n </h3>\n\n @if (status() === 'success') {\n @if (description()) {\n <p class=\"tk-process-steps__result-description\">{{ description() }}</p>\n }\n } @else if (errors().length || description()) {\n <tk-message [severity]=\"resultMessageSeverity()\" class=\"tk-process-steps__result-message\">\n @if (errors().length) {\n <ul class=\"tk-process-steps__result-errors\">\n @for (error of errors(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n } @else {\n {{ description() }}\n }\n </tk-message>\n }\n }\n\n @if (countdownText(); as countdownText) {\n <p\n class=\"tk-process-steps__result-countdown\"\n [class.tk-process-steps__result-countdown--success]=\"status() === 'success'\"\n [class.tk-process-steps__result-countdown--error]=\"status() === 'error'\"\n [class.tk-process-steps__result-countdown--warning]=\"status() === 'warning'\">\n {{ countdownText }}\n </p>\n }\n }\n</output>\n", styles: [":host{display:block}.tk-process-steps{display:flex;flex-direction:column;align-items:center;padding:var(--tk-spacing-padding-xl);gap:var(--tk-spacing-gap-m);text-align:center}.tk-process-steps--compact{padding:0}.tk-process-steps__spinner-wrapper{position:relative;display:inline-flex;align-items:center;justify-content:center}.tk-process-steps__spinner-progress{width:var(--tk-size-base-500);height:var(--tk-size-base-500)}.tk-process-steps__spinner-icon{position:absolute;pointer-events:none;color:var(--tk-color-primary-strong)}.tk-process-steps__title{font-size:var(--tk-font-size-base-125);font-weight:var(--tk-font-weight-600);color:var(--tk-color-text-default);margin:0}.tk-process-steps__description{font-size:var(--tk-font-size-base-88);color:var(--tk-color-text-subtle);max-width:28rem;margin:0;line-height:1.6}.tk-process-steps__steps{width:100%;max-width:28rem;margin:0 auto;display:flex;flex-direction:column;gap:var(--tk-spacing-gap-m, 1rem);text-align:left;list-style:none;padding:0}.tk-process-steps--compact .tk-process-steps__steps{background:var(--tk-color-background-soft);border-radius:var(--tk-borderRadius-m);padding:var(--tk-spacing-base-100);max-width:none}.tk-process-steps__step{display:flex;align-items:flex-start;gap:var(--tk-spacing-gap-s);font-size:var(--tk-font-size-base-88)}.tk-process-steps__step-icon-wrapper{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:50%;flex-shrink:0}.tk-process-steps__step-icon-wrapper--done{background:var(--tk-color-feedback-success-muted)}.tk-process-steps__step-icon-wrapper--error{background:var(--tk-color-feedback-danger-muted)}.tk-process-steps__step-icon-wrapper--warning{background:var(--tk-color-feedback-warn-muted)}.tk-process-steps__step-content{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-xs);padding-top:.15rem}.tk-process-steps__step-spinner{display:inline-flex;align-items:center;justify-content:center;width:1.1rem;height:1.1rem;flex-shrink:0}.tk-process-steps__step-spinner ::ng-deep .p-progressspinner{width:1.1rem;height:1.1rem;margin:0}.tk-process-steps__step-spinner ::ng-deep svg{width:1.1rem!important;height:1.1rem!important}.tk-process-steps__step-dot{width:var(--tk-size-base-50);height:var(--tk-size-base-50);border-radius:50%;background:var(--tk-color-text-subtle);flex-shrink:0;opacity:.4}.tk-process-steps__step-label{color:var(--tk-color-text-subtle)}.tk-process-steps__step-description{font-size:var(--tk-font-size-base-75);font-weight:var(--tk-font-weight-400);color:var(--tk-color-text-subtle)}.tk-process-steps__step--active .tk-process-steps__step-label{color:var(--tk-color-primary-default);font-weight:var(--tk-font-weight-600)}.tk-process-steps__step--done .tk-process-steps__step-label{color:var(--tk-color-feedback-success-strong);font-weight:var(--tk-font-weight-600)}.tk-process-steps__step--error .tk-process-steps__step-label{color:var(--tk-color-feedback-danger-strong);font-weight:var(--tk-font-weight-600)}.tk-process-steps__step--warning .tk-process-steps__step-label{color:var(--tk-color-feedback-warn-strong);font-weight:var(--tk-font-weight-600)}.tk-process-steps__banner{text-align:left}.tk-process-steps__result-circle{width:var(--tk-size-base-500);height:var(--tk-size-base-500);border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0}.tk-process-steps__result-circle--success{background:var(--tk-color-feedback-success-muted)}.tk-process-steps__result-circle--error{background:var(--tk-color-feedback-danger-muted)}.tk-process-steps__result-circle--warning{background:var(--tk-color-feedback-warn-muted)}.tk-process-steps__result-title{font-size:var(--tk-font-size-base-125);font-weight:var(--tk-font-weight-600);margin:0}.tk-process-steps__result-title--success{color:var(--tk-color-feedback-success-strong)}.tk-process-steps__result-title--error{color:var(--tk-color-feedback-danger-strong)}.tk-process-steps__result-title--warning{color:var(--tk-color-feedback-warn-strong)}.tk-process-steps__result-description{font-size:var(--tk-font-size-base-100);color:var(--tk-color-text-subtle);max-width:22rem;margin:0;line-height:1.6}.tk-process-steps__result-message{text-align:left}.tk-process-steps__result-errors{margin:0;padding-left:var(--tk-spacing-padding-l);display:flex;flex-direction:column;gap:var(--tk-spacing-gap-xs)}.tk-process-steps__result-countdown{font-size:var(--tk-font-size-base-88);color:var(--tk-color-text-subtle);margin:0}.tk-process-steps__result-countdown--success{color:var(--tk-color-feedback-success-strong)}.tk-process-steps__result-countdown--error{color:var(--tk-color-feedback-danger-strong)}.tk-process-steps__result-countdown--warning{color:var(--tk-color-feedback-warn-strong)}.tk-process-steps__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"], dependencies: [{ kind: "component", type: ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: IconComponent, selector: "tk-icon", inputs: ["icon", "styleIcon", "color", "size", "disabled"] }, { kind: "component", type: MessageComponent, selector: "tk-message", inputs: ["severity", "closable"], outputs: ["closed"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
121
|
+
}
|
|
122
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.17", ngImport: i0, type: ProcessStepsComponent, decorators: [{
|
|
123
|
+
type: Component,
|
|
124
|
+
args: [{ selector: 'tk-process-steps', changeDetection: ChangeDetectionStrategy.OnPush, imports: [ProgressSpinner, IconComponent, MessageComponent], template: "<output class=\"tk-process-steps\" [class.tk-process-steps--compact]=\"compact()\">\n @if (status() === 'progress' && showIcon()) {\n <div class=\"tk-process-steps__spinner-wrapper\" aria-hidden=\"true\">\n <p-progressSpinner\n class=\"tk-process-steps__spinner-progress\"\n strokeWidth=\"3\"\n animationDuration=\"1s\" />\n <tk-icon\n [icon]=\"icon()\"\n styleIcon=\"fal\"\n size=\"lg\"\n class=\"tk-process-steps__spinner-icon\" />\n </div>\n }\n\n @if (status() === 'progress' && !compact()) {\n <h3 class=\"tk-process-steps__title\">{{ title() }}</h3>\n @if (description()) {\n <p class=\"tk-process-steps__description\">{{ description() }}</p>\n }\n }\n\n @if (status() === 'progress' || compact()) {\n <ul class=\"tk-process-steps__steps\">\n @for (step of steps(); track step.label) {\n <li\n class=\"tk-process-steps__step\"\n [class.tk-process-steps__step--active]=\"step.state === 'active'\"\n [class.tk-process-steps__step--done]=\"step.state === 'done'\"\n [class.tk-process-steps__step--error]=\"step.state === 'error'\"\n [class.tk-process-steps__step--warning]=\"step.state === 'warning'\"\n [attr.aria-current]=\"step.state === 'active' ? 'step' : null\">\n <span\n class=\"tk-process-steps__step-icon-wrapper\"\n [class.tk-process-steps__step-icon-wrapper--done]=\"step.state === 'done'\"\n [class.tk-process-steps__step-icon-wrapper--error]=\"step.state === 'error'\"\n [class.tk-process-steps__step-icon-wrapper--warning]=\"step.state === 'warning'\">\n @switch (step.state) {\n @case ('done') {\n <tk-icon\n icon=\"circle-check\"\n styleIcon=\"fal\"\n size=\"1x\"\n color=\"success\"\n class=\"tk-process-steps__step-icon--done\"\n aria-hidden=\"true\" />\n }\n @case ('error') {\n <tk-icon\n icon=\"circle-xmark\"\n styleIcon=\"fal\"\n size=\"1x\"\n color=\"danger\"\n class=\"tk-process-steps__step-icon--error\"\n aria-hidden=\"true\" />\n }\n @case ('warning') {\n <tk-icon\n icon=\"triangle-exclamation\"\n styleIcon=\"fal\"\n size=\"1x\"\n color=\"warning\"\n class=\"tk-process-steps__step-icon--warning\"\n aria-hidden=\"true\" />\n }\n @case ('active') {\n <span class=\"tk-process-steps__step-spinner\" aria-hidden=\"true\">\n <p-progressSpinner strokeWidth=\"5\" animationDuration=\"0.8s\" />\n </span>\n }\n @default {\n <span class=\"tk-process-steps__step-dot\" aria-hidden=\"true\"></span>\n }\n }\n </span>\n <span class=\"tk-process-steps__step-content\">\n <span class=\"tk-process-steps__step-label\">\n {{ step.label }}\n <span class=\"tk-process-steps__sr-only\">({{ stepStatusLabel(step.state) }})</span>\n </span>\n @if (step.description) {\n <span class=\"tk-process-steps__step-description\">{{ step.description }}</span>\n }\n </span>\n </li>\n }\n </ul>\n }\n\n @if (status() !== 'progress') {\n @if (compact()) {\n @if (errors().length || description()) {\n <tk-message [severity]=\"bannerSeverity()\" class=\"tk-process-steps__banner\">\n @if (errors().length) {\n <ul class=\"tk-process-steps__result-errors\">\n @for (error of errors(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n } @else {\n {{ description() }}\n }\n </tk-message>\n }\n } @else {\n <div\n class=\"tk-process-steps__result-circle\"\n [class.tk-process-steps__result-circle--success]=\"status() === 'success'\"\n [class.tk-process-steps__result-circle--error]=\"status() === 'error'\"\n [class.tk-process-steps__result-circle--warning]=\"status() === 'warning'\">\n <tk-icon\n [icon]=\"resultIcon()\"\n styleIcon=\"fal\"\n size=\"2x\"\n [color]=\"resultColor()\"\n aria-hidden=\"true\" />\n </div>\n <h3\n class=\"tk-process-steps__result-title\"\n [class.tk-process-steps__result-title--success]=\"status() === 'success'\"\n [class.tk-process-steps__result-title--error]=\"status() === 'error'\"\n [class.tk-process-steps__result-title--warning]=\"status() === 'warning'\">\n {{ title() }}\n </h3>\n\n @if (status() === 'success') {\n @if (description()) {\n <p class=\"tk-process-steps__result-description\">{{ description() }}</p>\n }\n } @else if (errors().length || description()) {\n <tk-message [severity]=\"resultMessageSeverity()\" class=\"tk-process-steps__result-message\">\n @if (errors().length) {\n <ul class=\"tk-process-steps__result-errors\">\n @for (error of errors(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n } @else {\n {{ description() }}\n }\n </tk-message>\n }\n }\n\n @if (countdownText(); as countdownText) {\n <p\n class=\"tk-process-steps__result-countdown\"\n [class.tk-process-steps__result-countdown--success]=\"status() === 'success'\"\n [class.tk-process-steps__result-countdown--error]=\"status() === 'error'\"\n [class.tk-process-steps__result-countdown--warning]=\"status() === 'warning'\">\n {{ countdownText }}\n </p>\n }\n }\n</output>\n", styles: [":host{display:block}.tk-process-steps{display:flex;flex-direction:column;align-items:center;padding:var(--tk-spacing-padding-xl);gap:var(--tk-spacing-gap-m);text-align:center}.tk-process-steps--compact{padding:0}.tk-process-steps__spinner-wrapper{position:relative;display:inline-flex;align-items:center;justify-content:center}.tk-process-steps__spinner-progress{width:var(--tk-size-base-500);height:var(--tk-size-base-500)}.tk-process-steps__spinner-icon{position:absolute;pointer-events:none;color:var(--tk-color-primary-strong)}.tk-process-steps__title{font-size:var(--tk-font-size-base-125);font-weight:var(--tk-font-weight-600);color:var(--tk-color-text-default);margin:0}.tk-process-steps__description{font-size:var(--tk-font-size-base-88);color:var(--tk-color-text-subtle);max-width:28rem;margin:0;line-height:1.6}.tk-process-steps__steps{width:100%;max-width:28rem;margin:0 auto;display:flex;flex-direction:column;gap:var(--tk-spacing-gap-m, 1rem);text-align:left;list-style:none;padding:0}.tk-process-steps--compact .tk-process-steps__steps{background:var(--tk-color-background-soft);border-radius:var(--tk-borderRadius-m);padding:var(--tk-spacing-base-100);max-width:none}.tk-process-steps__step{display:flex;align-items:flex-start;gap:var(--tk-spacing-gap-s);font-size:var(--tk-font-size-base-88)}.tk-process-steps__step-icon-wrapper{display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;border-radius:50%;flex-shrink:0}.tk-process-steps__step-icon-wrapper--done{background:var(--tk-color-feedback-success-muted)}.tk-process-steps__step-icon-wrapper--error{background:var(--tk-color-feedback-danger-muted)}.tk-process-steps__step-icon-wrapper--warning{background:var(--tk-color-feedback-warn-muted)}.tk-process-steps__step-content{display:flex;flex-direction:column;gap:var(--tk-spacing-gap-xs);padding-top:.15rem}.tk-process-steps__step-spinner{display:inline-flex;align-items:center;justify-content:center;width:1.1rem;height:1.1rem;flex-shrink:0}.tk-process-steps__step-spinner ::ng-deep .p-progressspinner{width:1.1rem;height:1.1rem;margin:0}.tk-process-steps__step-spinner ::ng-deep svg{width:1.1rem!important;height:1.1rem!important}.tk-process-steps__step-dot{width:var(--tk-size-base-50);height:var(--tk-size-base-50);border-radius:50%;background:var(--tk-color-text-subtle);flex-shrink:0;opacity:.4}.tk-process-steps__step-label{color:var(--tk-color-text-subtle)}.tk-process-steps__step-description{font-size:var(--tk-font-size-base-75);font-weight:var(--tk-font-weight-400);color:var(--tk-color-text-subtle)}.tk-process-steps__step--active .tk-process-steps__step-label{color:var(--tk-color-primary-default);font-weight:var(--tk-font-weight-600)}.tk-process-steps__step--done .tk-process-steps__step-label{color:var(--tk-color-feedback-success-strong);font-weight:var(--tk-font-weight-600)}.tk-process-steps__step--error .tk-process-steps__step-label{color:var(--tk-color-feedback-danger-strong);font-weight:var(--tk-font-weight-600)}.tk-process-steps__step--warning .tk-process-steps__step-label{color:var(--tk-color-feedback-warn-strong);font-weight:var(--tk-font-weight-600)}.tk-process-steps__banner{text-align:left}.tk-process-steps__result-circle{width:var(--tk-size-base-500);height:var(--tk-size-base-500);border-radius:50%;display:flex;align-items:center;justify-content:center;flex-shrink:0}.tk-process-steps__result-circle--success{background:var(--tk-color-feedback-success-muted)}.tk-process-steps__result-circle--error{background:var(--tk-color-feedback-danger-muted)}.tk-process-steps__result-circle--warning{background:var(--tk-color-feedback-warn-muted)}.tk-process-steps__result-title{font-size:var(--tk-font-size-base-125);font-weight:var(--tk-font-weight-600);margin:0}.tk-process-steps__result-title--success{color:var(--tk-color-feedback-success-strong)}.tk-process-steps__result-title--error{color:var(--tk-color-feedback-danger-strong)}.tk-process-steps__result-title--warning{color:var(--tk-color-feedback-warn-strong)}.tk-process-steps__result-description{font-size:var(--tk-font-size-base-100);color:var(--tk-color-text-subtle);max-width:22rem;margin:0;line-height:1.6}.tk-process-steps__result-message{text-align:left}.tk-process-steps__result-errors{margin:0;padding-left:var(--tk-spacing-padding-l);display:flex;flex-direction:column;gap:var(--tk-spacing-gap-xs)}.tk-process-steps__result-countdown{font-size:var(--tk-font-size-base-88);color:var(--tk-color-text-subtle);margin:0}.tk-process-steps__result-countdown--success{color:var(--tk-color-feedback-success-strong)}.tk-process-steps__result-countdown--error{color:var(--tk-color-feedback-danger-strong)}.tk-process-steps__result-countdown--warning{color:var(--tk-color-feedback-warn-strong)}.tk-process-steps__sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"] }]
|
|
125
|
+
}], ctorParameters: () => [], propDecorators: { steps: [{ type: i0.Input, args: [{ isSignal: true, alias: "steps", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: true }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], status: [{ type: i0.Input, args: [{ isSignal: true, alias: "status", required: false }] }], showIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "showIcon", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], countdownSeconds: [{ type: i0.Input, args: [{ isSignal: true, alias: "countdownSeconds", required: false }] }], countdownLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "countdownLabel", required: false }] }], countdownFinished: [{ type: i0.Output, args: ["countdownFinished"] }] } });
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Generated bundle index. Do not edit.
|
|
129
|
+
*/
|
|
130
|
+
|
|
131
|
+
export { ProcessStepsComponent };
|
|
132
|
+
//# sourceMappingURL=tekus-design-system-components-process-steps.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tekus-design-system-components-process-steps.mjs","sources":["../../../projects/design-system/components/process-steps/src/process-steps.component.ts","../../../projects/design-system/components/process-steps/src/process-steps.component.html","../../../projects/design-system/components/process-steps/tekus-design-system-components-process-steps.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n EffectCleanupRegisterFn,\n input,\n output,\n signal,\n} from '@angular/core';\nimport { ProgressSpinner } from 'primeng/progressspinner';\nimport { IconComponent } from '@tekus/design-system/components/icon';\nimport { MessageComponent } from '@tekus/design-system/components/message';\nimport { ProcessStep, ProcessStepsStatus, StepState } from './process-steps.types';\n\n@Component({\n selector: 'tk-process-steps',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [ProgressSpinner, IconComponent, MessageComponent],\n templateUrl: './process-steps.component.html',\n styleUrl: './process-steps.component.scss'\n})\nexport class ProcessStepsComponent {\n readonly steps = input<ProcessStep[]>([]);\n readonly title = input.required<string>();\n readonly description = input<string>();\n readonly icon = input<string>('gears');\n readonly status = input<ProcessStepsStatus>('progress');\n\n /** Whether to show the spinner + icon header while `status` is `progress`. */\n readonly showIcon = input<boolean>(true);\n\n /**\n * Strips the panel down to just the step list: no padding, and no\n * `title`/`description` header while `status` is `progress` — for hosts\n * that provide their own framing (e.g. a card) and already show the file\n * name elsewhere. The final result view (`success`/`error`/`warning`)\n * still shows its own title/message, since that's the only place the\n * outcome text is surfaced.\n */\n readonly compact = input<boolean>(false);\n\n /** Specific problems to list inside the result message box (ignored when `status` is `success`). */\n readonly errors = input<string[]>([]);\n\n /** Seconds until the countdown finishes; omit to disable it. */\n readonly countdownSeconds = input<number>();\n\n /**\n * Countdown text; `{seconds}` is replaced with the seconds left. Defaults to a \"closing\"\n * message, but the countdown isn't only for closing — override it to match what\n * `(countdownFinished)` actually does.\n */\n readonly countdownLabel = input<string>('Closing in {seconds}s…');\n\n /** Emitted once when the countdown reaches zero — the consumer decides what happens next (close a modal, show a toast, etc.). */\n readonly countdownFinished = output<void>();\n\n /** Seconds left in the countdown, or `undefined` while it's disabled. */\n readonly remainingSeconds = signal<number | undefined>(undefined);\n\n constructor() {\n effect(onCleanup => this.runCountdown(onCleanup));\n }\n\n /** Starts (or disables) the countdown whenever `status`/`countdownSeconds` change. */\n private runCountdown(onCleanup: EffectCleanupRegisterFn): void {\n const total = this.countdownSeconds();\n if (this.status() === 'progress' || !total) {\n this.remainingSeconds.set(undefined);\n return;\n }\n\n this.remainingSeconds.set(total);\n const intervalId = setInterval(() => this.tickCountdown(intervalId), 1000);\n onCleanup(() => clearInterval(intervalId));\n }\n\n /** Decrements `remainingSeconds` by one and emits `countdownFinished` once it bottoms out. */\n private tickCountdown(intervalId: ReturnType<typeof setInterval>): void {\n const next = (this.remainingSeconds() ?? 1) - 1;\n this.remainingSeconds.set(Math.max(next, 0));\n if (next <= 0) {\n clearInterval(intervalId);\n this.countdownFinished.emit();\n }\n }\n\n /**\n * Accessible suffix announced per step since state is otherwise\n * conveyed only through color/icon.\n */\n stepStatusLabel(state: StepState): string {\n switch (state) {\n case 'done':\n return 'completed';\n case 'active':\n return 'in progress';\n case 'error':\n return 'failed';\n case 'warning':\n return 'needs attention';\n default:\n return 'pending';\n }\n }\n\n readonly resultIcon = computed<string>(() => {\n switch (this.status()) {\n case 'error':\n return 'xmark';\n case 'warning':\n return 'triangle-exclamation';\n default:\n return 'check';\n }\n });\n\n readonly resultColor = computed<'success' | 'danger' | 'warning'>(() => {\n switch (this.status()) {\n case 'error':\n return 'danger';\n case 'warning':\n return 'warning';\n default:\n return 'success';\n }\n });\n\n /** Severity for the message box wrapping `description`/`errors` (success has no box). */\n readonly resultMessageSeverity = computed<'error' | 'warn'>(() =>\n this.status() === 'error' ? 'error' : 'warn'\n );\n\n /** Severity for the compact terminal banner (`tk-message`) — unlike `resultMessageSeverity`, success gets its own box here. */\n readonly bannerSeverity = computed<'success' | 'error' | 'warn'>(() => {\n if (this.status() === 'error') {\n return 'error';\n }\n if (this.status() === 'warning') {\n return 'warn';\n }\n return 'success';\n });\n\n /** `countdownLabel` with `{seconds}` filled in, or `undefined` while the countdown is disabled. */\n readonly countdownText = computed<string | undefined>(() => {\n const seconds = this.remainingSeconds();\n if (seconds === undefined) {\n return undefined;\n }\n return this.countdownLabel().replace('{seconds}', String(seconds));\n });\n}\n","<output class=\"tk-process-steps\" [class.tk-process-steps--compact]=\"compact()\">\n @if (status() === 'progress' && showIcon()) {\n <div class=\"tk-process-steps__spinner-wrapper\" aria-hidden=\"true\">\n <p-progressSpinner\n class=\"tk-process-steps__spinner-progress\"\n strokeWidth=\"3\"\n animationDuration=\"1s\" />\n <tk-icon\n [icon]=\"icon()\"\n styleIcon=\"fal\"\n size=\"lg\"\n class=\"tk-process-steps__spinner-icon\" />\n </div>\n }\n\n @if (status() === 'progress' && !compact()) {\n <h3 class=\"tk-process-steps__title\">{{ title() }}</h3>\n @if (description()) {\n <p class=\"tk-process-steps__description\">{{ description() }}</p>\n }\n }\n\n @if (status() === 'progress' || compact()) {\n <ul class=\"tk-process-steps__steps\">\n @for (step of steps(); track step.label) {\n <li\n class=\"tk-process-steps__step\"\n [class.tk-process-steps__step--active]=\"step.state === 'active'\"\n [class.tk-process-steps__step--done]=\"step.state === 'done'\"\n [class.tk-process-steps__step--error]=\"step.state === 'error'\"\n [class.tk-process-steps__step--warning]=\"step.state === 'warning'\"\n [attr.aria-current]=\"step.state === 'active' ? 'step' : null\">\n <span\n class=\"tk-process-steps__step-icon-wrapper\"\n [class.tk-process-steps__step-icon-wrapper--done]=\"step.state === 'done'\"\n [class.tk-process-steps__step-icon-wrapper--error]=\"step.state === 'error'\"\n [class.tk-process-steps__step-icon-wrapper--warning]=\"step.state === 'warning'\">\n @switch (step.state) {\n @case ('done') {\n <tk-icon\n icon=\"circle-check\"\n styleIcon=\"fal\"\n size=\"1x\"\n color=\"success\"\n class=\"tk-process-steps__step-icon--done\"\n aria-hidden=\"true\" />\n }\n @case ('error') {\n <tk-icon\n icon=\"circle-xmark\"\n styleIcon=\"fal\"\n size=\"1x\"\n color=\"danger\"\n class=\"tk-process-steps__step-icon--error\"\n aria-hidden=\"true\" />\n }\n @case ('warning') {\n <tk-icon\n icon=\"triangle-exclamation\"\n styleIcon=\"fal\"\n size=\"1x\"\n color=\"warning\"\n class=\"tk-process-steps__step-icon--warning\"\n aria-hidden=\"true\" />\n }\n @case ('active') {\n <span class=\"tk-process-steps__step-spinner\" aria-hidden=\"true\">\n <p-progressSpinner strokeWidth=\"5\" animationDuration=\"0.8s\" />\n </span>\n }\n @default {\n <span class=\"tk-process-steps__step-dot\" aria-hidden=\"true\"></span>\n }\n }\n </span>\n <span class=\"tk-process-steps__step-content\">\n <span class=\"tk-process-steps__step-label\">\n {{ step.label }}\n <span class=\"tk-process-steps__sr-only\">({{ stepStatusLabel(step.state) }})</span>\n </span>\n @if (step.description) {\n <span class=\"tk-process-steps__step-description\">{{ step.description }}</span>\n }\n </span>\n </li>\n }\n </ul>\n }\n\n @if (status() !== 'progress') {\n @if (compact()) {\n @if (errors().length || description()) {\n <tk-message [severity]=\"bannerSeverity()\" class=\"tk-process-steps__banner\">\n @if (errors().length) {\n <ul class=\"tk-process-steps__result-errors\">\n @for (error of errors(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n } @else {\n {{ description() }}\n }\n </tk-message>\n }\n } @else {\n <div\n class=\"tk-process-steps__result-circle\"\n [class.tk-process-steps__result-circle--success]=\"status() === 'success'\"\n [class.tk-process-steps__result-circle--error]=\"status() === 'error'\"\n [class.tk-process-steps__result-circle--warning]=\"status() === 'warning'\">\n <tk-icon\n [icon]=\"resultIcon()\"\n styleIcon=\"fal\"\n size=\"2x\"\n [color]=\"resultColor()\"\n aria-hidden=\"true\" />\n </div>\n <h3\n class=\"tk-process-steps__result-title\"\n [class.tk-process-steps__result-title--success]=\"status() === 'success'\"\n [class.tk-process-steps__result-title--error]=\"status() === 'error'\"\n [class.tk-process-steps__result-title--warning]=\"status() === 'warning'\">\n {{ title() }}\n </h3>\n\n @if (status() === 'success') {\n @if (description()) {\n <p class=\"tk-process-steps__result-description\">{{ description() }}</p>\n }\n } @else if (errors().length || description()) {\n <tk-message [severity]=\"resultMessageSeverity()\" class=\"tk-process-steps__result-message\">\n @if (errors().length) {\n <ul class=\"tk-process-steps__result-errors\">\n @for (error of errors(); track error) {\n <li>{{ error }}</li>\n }\n </ul>\n } @else {\n {{ description() }}\n }\n </tk-message>\n }\n }\n\n @if (countdownText(); as countdownText) {\n <p\n class=\"tk-process-steps__result-countdown\"\n [class.tk-process-steps__result-countdown--success]=\"status() === 'success'\"\n [class.tk-process-steps__result-countdown--error]=\"status() === 'error'\"\n [class.tk-process-steps__result-countdown--warning]=\"status() === 'warning'\">\n {{ countdownText }}\n </p>\n }\n }\n</output>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|