@sixbell-telco/sdk
Version:
A collection of reusable components designed for use in Sixbell Telco Angular projects
935 lines (928 loc) • 52.9 kB
JavaScript
import * as i0 from '@angular/core';
import { signal, computed, Injectable, input, ChangeDetectionStrategy, Component, inject, contentChildren, output } from '@angular/core';
import { CommonModule, NgClass } from '@angular/common';
import { cn } from '@sixbell-telco/sdk/utils/cn';
import { toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { matChevronLeftOutline, matChevronRightOutline, matKeyboardReturnOutline, matSaveOutline } from '@ng-icons/material-icons/outline';
import { TranslateService, _, TranslatePipe } from '@ngx-translate/core';
import { ButtonComponent } from '@sixbell-telco/sdk/components/button';
import { IconComponent } from '@sixbell-telco/sdk/components/icon';
import { TypographyDirective } from '@sixbell-telco/sdk/directives/typography';
import { matCheckOutline } from '@sixbell-telco/sdk/components/icon/material/outline';
/**
* Enum-like object representing possible wizard step statuses
* @readonly
* @enum {string}
*/
const WIZARD_STEP_STATUS = {
IN_PROGRESS: 'in progress',
PENDING: 'pending',
COMPLETED: 'completed',
};
/**
* Service for managing wizard state and navigation
* @Injectable
*/
class WizardService {
// State signals
/** @private Internal signal for wizard steps */
_steps = signal([]);
/** @private Internal signal for current step index */
_currentStepIndex = signal(0);
/** @private Internal signal for first step index */
_fistStepIndex = signal(0);
/** @private Internal signal for last step index */
_lastStepIndex = signal(0);
/** @private Internal signal for transition state */
_isTransitioning = signal(false);
// Readonly signals
/** Readonly array of wizard steps */
steps = this._steps.asReadonly();
/**
* Current step index
* @readonly
*/
currentStepIndex = this._currentStepIndex.asReadonly();
/**
* Currently active step
* @readonly
*/
currentStep = computed(() => this.steps()[this.currentStepIndex()]);
/**
* Array of valid steps
* @readonly
*/
validSteps = computed(() => this.steps().filter((step) => step.isValid));
/**
* Indicates if all steps are valid
* @readonly
*/
areAllStepsValid = computed(() => this.validSteps().length === this.steps().length);
/**
* First step index
* @readonly
*/
fistStepIndex = this._fistStepIndex.asReadonly();
/**
* First step in the wizard
* @readonly
*/
firstStep = computed(() => this.steps()[this.fistStepIndex()]);
/**
* Last step index
* @readonly
*/
lastStepIndex = this._lastStepIndex.asReadonly();
/**
* Last step in the wizard
* @readonly
*/
lastStep = computed(() => this.steps()[this.lastStepIndex()]);
/**
* Completed steps
* @readonly
*/
completedSteps = computed(() => this.steps().filter((step) => step.status === 'completed'));
/**
* Pending steps
* @readonly
*/
pendingSteps = computed(() => this.steps().filter((step) => step.status === 'pending'));
/**
* In-progress steps
* @readonly
*/
inProgressSteps = computed(() => this.steps().filter((step) => step.status === 'in progress'));
/**
* Indicates if all steps are completed
* @readonly
*/
isCompleted = computed(() => this.completedSteps().length === this.steps().length);
/**
* Indicates if current step is the first step
* @readonly
*/
isCurrentStepFirst = computed(() => this.currentStepIndex() === this.fistStepIndex());
/**
* Indicates if current step is the last step
* @readonly
*/
isCurrentStepLast = computed(() => this.currentStepIndex() === this.lastStepIndex());
/**
* Indicates if wizard is transitioning between steps
* @readonly
*/
isTransitioning = this._isTransitioning.asReadonly();
/**
* Initializes the wizard with given steps
* @param {WizardStep[]} steps - Array of step configurations
*/
init(steps) {
this.setSteps(steps.map((step, index) => ({
...step,
status: index === 0 ? 'in progress' : 'pending',
isValid: false,
})));
this.setFistStepIndex(0);
this.setLastStepIndex(steps.length - 1);
}
/**
* Replaces all steps with new configuration
* @param {WizardStepConfig[]} steps - New array of step configurations
*/
setSteps(steps) {
this._steps.set(steps);
}
/**
* Adds a new step to the end of the wizard
* @param {WizardStepConfig} step - Step configuration to add
*/
addStep(step) {
this.setSteps([...this.steps(), step]);
}
/**
* Inserts a step at specific index
* @param {number} index - Position to insert the step
* @param {WizardStepConfig} step - Step configuration to add
*/
addStepAtIndex(index, step) {
const newSteps = this.steps().reduce((acc, s, i) => {
if (i === index) {
acc.push(step);
}
acc.push(s);
return acc;
}, []);
this.setSteps(newSteps);
}
/**
* Removes step at specified index
* @param {number} index - Index of step to remove
*/
removeStep(index) {
const newSteps = this.steps().filter((_, i) => i !== index);
this.setSteps(newSteps);
}
/**
* Updates name of step at specified index
* @param {number} index - Index of step to update
* @param {string} name - New name for the step
*/
updateStepName(index, name) {
const newSteps = this.steps().map((s, i) => (i === index ? { ...s, name } : s));
this.setSteps(newSteps);
}
/**
* Updates label of step at specified index
* @param {number} index - Index of step to update
* @param {string} label - New label for the step
*/
updateStepLabel(index, label) {
const newSteps = this.steps().map((s, i) => (i === index ? { ...s, label } : s));
this.setSteps(newSteps);
}
/**
* Updates status of step at specified index
* @param {number} index - Index of step to update
* @param {WizardStepStatus} status - New status for the step
* @param {number} [stale] - Optional delay in milliseconds before applying changes
*/
updateStepStatus(index, status, stale) {
const newSteps = this.steps().map((s, i) => (i === index ? { ...s, status } : s));
this._isTransitioning.set(true);
if (stale === undefined) {
this._isTransitioning.set(false);
this.setSteps(newSteps);
return;
}
setTimeout(() => {
this._isTransitioning.set(false);
this.setSteps(newSteps);
}, stale);
}
/**
* Updates validation status of step at specified index
* @param {number} index - Index of step to update
* @param {boolean} isValid - New validation status
*/
updateStepIsValid(index, isValid) {
const newSteps = this.steps().map((s, i) => (i === index ? { ...s, isValid } : s));
this.setSteps(newSteps);
}
/**
* Replaces entire step configuration at specified index
* @param {number} index - Index of step to replace
* @param {WizardStepConfig} step - New step configuration
*/
updateStep(index, step) {
const newSteps = this.steps().map((s, i) => (i === index ? step : s));
this.setSteps(newSteps);
}
/**
* Sets current active step index
* @param {number} index - New current step index
*/
setCurrentStepIndex(index) {
this._currentStepIndex.set(index);
}
/**
* Sets index for first step in wizard
* @param {number} index - New first step index
*/
setFistStepIndex(index) {
this._fistStepIndex.set(index);
}
/**
* Sets index for last step in wizard
* @param {number} index - New last step index
*/
setLastStepIndex(index) {
this._lastStepIndex.set(index);
}
/**
* Navigates to next valid step
*/
nextStep() {
if (!this.currentStep().isValid)
return;
const lastIndex = this._steps().length - 1;
const nextIndex = this.currentStepIndex() + 1;
if (nextIndex > lastIndex)
return;
const nextStepIndex = nextIndex;
this.updateStepStatus(this.currentStepIndex(), 'completed');
this._currentStepIndex.set(nextStepIndex);
this.updateStepStatus(nextStepIndex, 'in progress', 300);
}
/**
* Navigates to previous step
*/
previousStep() {
if (this.currentStepIndex() <= 0)
return;
const previousStepIndex = this.currentStepIndex() - 1;
this.updateStepStatus(this.currentStepIndex(), 'pending');
this._currentStepIndex.set(previousStepIndex);
this.updateStepStatus(previousStepIndex, 'in progress', 300);
}
/**
* Jumps to specified step index
* @param {number} index - Target step index to navigate to
*/
gotoStep(index) {
if (index < 0 || index >= this.steps().length)
return;
const newSteps = this.steps().map((step, i) => {
if (i === index) {
return { ...step, status: WIZARD_STEP_STATUS.IN_PROGRESS };
}
if (index === this.fistStepIndex()) {
if (i === this.fistStepIndex()) {
return { ...step, status: WIZARD_STEP_STATUS.IN_PROGRESS };
}
return { ...step, status: WIZARD_STEP_STATUS.PENDING };
}
if (index === this.lastStepIndex()) {
if (i === this.lastStepIndex()) {
return { ...step, status: WIZARD_STEP_STATUS.IN_PROGRESS };
}
return { ...step, status: WIZARD_STEP_STATUS.COMPLETED };
}
if (i < index) {
return { ...step, status: WIZARD_STEP_STATUS.COMPLETED };
}
if (i > index) {
return { ...step, status: WIZARD_STEP_STATUS.PENDING };
}
return step;
});
this.setSteps(newSteps);
this._currentStepIndex.set(index);
}
/**
* Resets wizard to initial state
*/
reset() {
this._steps.set([]);
this._currentStepIndex.set(0);
this._fistStepIndex.set(0);
this._lastStepIndex.set(0);
this._isTransitioning.set(false);
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardService, providedIn: 'root' });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root',
}]
}] });
class WizardActionsComponent {
// Base table properties
alignment = input('left');
componentClass = computed(() => {
return cn('flex flex-w items-center gap-2', {
'justify-start': this.alignment() === 'left',
'justify-end': this.alignment() === 'right',
'justify-center': this.alignment() === 'center',
});
});
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardActionsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.0", type: WizardActionsComponent, isStandalone: true, selector: "st-wizard-actions", inputs: { alignment: { classPropertyName: "alignment", publicName: "alignment", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div [class]=\"componentClass()\">\n\t<ng-content></ng-content>\n</div>\n", dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardActionsComponent, decorators: [{
type: Component,
args: [{ selector: 'st-wizard-actions', imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"componentClass()\">\n\t<ng-content></ng-content>\n</div>\n" }]
}] });
/**
* Component wrapper for individual wizard step content with validation integration.
*
* @remarks
* Manages content visibility and validation state synchronization with the wizard service.
* Automatically handles:
* - Step activation status
* - Validation state propagation
* - Fade animations
* - Destruction cleanup
*
* @example
* ```html
* <st-wizard-content
* [stepIndex]="0"
* [isValid]="form.valid"
* >
* <!-- Step content -->
* </st-wizard-content>
* ```
*/
class WizardContentComponent {
/** @internal Injected wizard state service */
wizardService = inject(WizardService);
/**
* Position index in the wizard sequence (0-based)
* @default 0
*/
stepIndex = input(0);
/**
* Current validation state of the step
* @default false
* @remarks Updates wizard service automatically when changed
*/
isValid = input(false);
/**
* Computed status from wizard service
* @internal
*/
status = computed(() => this.wizardService.steps()[this.stepIndex()].status);
/**
* Observable version of isValid input
* @internal
*/
isValid$ = toObservable(this.isValid);
/**
* Current active step index from service
* @internal
*/
currentStep = computed(() => this.wizardService.currentStepIndex());
/**
* Checks if this content's step is currently active
* @returns {boolean} True if stepIndex matches current active step
* @internal
*/
isStepActive = computed(() => this.stepIndex() === this.wizardService.currentStepIndex());
/**
* Computed CSS classes for content container
* @returns {string} Animation classes
* @internal
*/
componentClass = computed(() => cn('animate-fade-in animate-duration-300'));
/**
* Sets up validation state synchronization
* @remarks Uses takeUntilDestroyed for automatic cleanup
*/
constructor() {
this.isValid$.pipe(takeUntilDestroyed()).subscribe((isValid) => {
this.wizardService.updateStepIsValid(this.stepIndex(), isValid);
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.0", type: WizardContentComponent, isStandalone: true, selector: "st-wizard-content", inputs: { stepIndex: { classPropertyName: "stepIndex", publicName: "stepIndex", isSignal: true, isRequired: false, transformFunction: null }, isValid: { classPropertyName: "isValid", publicName: "isValid", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (this.isStepActive()) {\n\t<div [class]=\"componentClass()\">\n\t\t<ng-content></ng-content>\n\t</div>\n}\n" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardContentComponent, decorators: [{
type: Component,
args: [{ selector: 'st-wizard-content', imports: [], template: "@if (this.isStepActive()) {\n\t<div [class]=\"componentClass()\">\n\t\t<ng-content></ng-content>\n\t</div>\n}\n" }]
}], ctorParameters: () => [] });
/**
* Component that displays a status badge for wizard steps with translated labels.
*
* @remarks
* Shows visual indicators for different step states with automatic translations.
* Supports three status types with corresponding styling:
* - Completed (green background)
* - In progress (neutral border)
* - Pending (dimmed appearance)
*
* Uses NGX-Translate for localization of status labels.
*
* @example
* ```html
* <!-- Completed state -->
* <st-wizard-marker [status]="'completed'"></st-wizard-marker>
*
* <!-- In progress state -->
* <st-wizard-marker [status]="'in progress'"></st-wizard-marker>
* ```
*/
class WizardMarkerComponent {
/** @internal Translation service instance */
translateService = inject(TranslateService);
/** @internal Wizard state service */
wizardService = inject(WizardService);
/**
* Current status of the associated wizard step
* @remarks Determines badge styling and label
*/
status = input.required();
/**
* Computed translated status message
* @internal
*/
statusMarkerMessage = computed(() => this.getStatusMarkerMessage());
/**
* Computed CSS classes for the status badge
* @internal
*/
statusMarkerClasses = computed(() => this.getStepStatusMarkerClasses());
/** @internal Signal holding translated "completed" text */
completed = signal('completed');
/** @internal Signal holding translated "in progress" text */
inProgress = signal('in progress');
/** @internal Signal holding translated "pending" text */
pending = signal('pending');
/** @internal Base CSS classes for the marker */
baseClasses = 'rounded-field transition-colors duration-300 ease-out delay-150';
/** @internal Status-to-class mapping */
statusClassMap = {
completed: 'bg-primary/20 text-primary px-3 py-[5px]',
'in progress': 'bg-neutral text-neutral-content border-[2px] border-neutral px-[10px] py-[3px]',
pending: 'bg-neutral/20 text-neutral-content/20 border-[2px] border-neutral px-[10px] py-[3px]',
};
/**
* Initializes component translations
* @remarks Loads translated status labels using NGX-Translate
*/
ngOnInit() {
this.initTranslatations();
}
/**
* Gets the appropriate translated status message
* @returns {string} Translated status label
* @internal
*/
getStatusMarkerMessage() {
return this.status() === 'completed' ? this.completed() : this.status() === 'in progress' ? this.inProgress() : this.pending();
}
/**
* Computes CSS classes based on current status
* @returns {string} Combined Tailwind classes
* @internal
*/
getStepStatusMarkerClasses() {
return cn(this.baseClasses, this.statusClassMap[this.status()]);
}
/**
* Initializes translations for status labels
* @remarks Uses translation keys:
* - 'sdk.wizard.wizardMarker.completed'
* - 'sdk.wizard.wizardMarker.inProgress'
* - 'sdk.wizard.wizardMarker.pending'
* @internal
*/
initTranslatations() {
this.translateService.get(_('sdk.wizard.wizardMarker.completed')).subscribe((res) => {
this.completed.set(res);
});
this.translateService.get(_('sdk.wizard.wizardMarker.inProgress')).subscribe((res) => {
this.inProgress.set(res);
});
this.translateService.get(_('sdk.wizard.wizardMarker.pending')).subscribe((res) => {
this.pending.set(res);
});
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardMarkerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.0", type: WizardMarkerComponent, isStandalone: true, selector: "st-wizard-marker", inputs: { status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div [class]=\"statusMarkerClasses()\">\n\t<span typography [tyVariant]=\"'body-xxs'\" [tyColor]=\"'inherit'\" [tyFontWeight]=\"'medium'\">{{ statusMarkerMessage() }}</span>\n</div>\n", dependencies: [{ kind: "directive", type: TypographyDirective, selector: "[typography]", inputs: ["tyVariant", "tyColor", "tyFontWeight", "tyTextOverflow"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardMarkerComponent, decorators: [{
type: Component,
args: [{ selector: 'st-wizard-marker', imports: [TypographyDirective], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"statusMarkerClasses()\">\n\t<span typography [tyVariant]=\"'body-xxs'\" [tyColor]=\"'inherit'\" [tyFontWeight]=\"'medium'\">{{ statusMarkerMessage() }}</span>\n</div>\n" }]
}] });
/**
* Visual indicator component for individual wizard steps with status-dependent styling and animations.
*
* @remarks
* Displays step progress through dynamic border and background colors. Supports three states:
* - Completed (checkmark icon)
* - In progress (highlighted border)
* - Pending (dimmed appearance)
*
* Uses Angular signals for optimized change detection and smooth transitions.
*
* @example
* ```html
* <!-- Completed step with custom icon -->
* <st-wizard-step
* [stepIndex]="1"
* [status]="'completed'"
* icon="user-profile"
* ></st-wizard-step>
*
* <!-- Current active step -->
* <st-wizard-step
* [stepIndex]="2"
* [status]="'in progress'"
* ></st-wizard-step>
* ```
*/
class WizardStepComponent {
/** @internal Injected wizard state service */
wizardService = inject(WizardService);
/**
* Optional custom icon name for completed state
* @default undefined (uses checkmark)
*/
icon = input();
/**
* Current progress status of the step
* @remarks Determines visual state and transitions
*/
status = input.required();
/**
* Position in wizard sequence (0-based index)
* @remarks Used for current step comparison
*/
stepIndex = input.required();
/** @internal Predefined checkmark icon */
iconCheck = matCheckOutline;
/**
* Computed CSS classes for step containers
* @returns {Object} Classes for outer/inner elements
* @remarks Applies:
* - 300ms color transitions
* - 300ms delay for pending states
* - Primary colors for active/completed states
* @internal
*/
stepClasses = computed(() => {
// Base classes
const baseOuterClasses = 'flex h-[50px] min-h-[50px] w-[50px] min-w-[50px] items-center justify-center rounded-full border-[1px] border-solid p-[2px] font-medium text-neutral-content';
const baseInnerClasses = 'flex h-full w-full items-center justify-center rounded-full bg-secondary';
// State variables
const isCurrentStep = this.wizardService.currentStepIndex() === this.stepIndex();
const currentStatus = this.status();
const isCompleted = currentStatus === 'completed';
const isInProgress = currentStatus === 'in progress';
// Conditions
const isCurrentActive = isCurrentStep && (isInProgress || isCompleted);
const isCompletedNotCurrent = !isCurrentStep && isCompleted;
const isPendingNotCurrent = !isCurrentStep && currentStatus === 'pending';
const outerClasses = cn(baseOuterClasses, {
'border-primary currentStep transition-colors duration-300 ease-out': isCurrentActive,
'border-primary notCurrentStep transition-colors duration-300 ease-out': isCompletedNotCurrent,
'border-secondary notCurrentStep transition-colors duration-300 ease-out delay-[300ms]': isPendingNotCurrent,
});
const innerClasses = cn(baseInnerClasses, {
'bg-primary text-primary-content currentStep transition-colors duration-300 ease-out': isCurrentActive,
'bg-primary text-primary-content notCurrentStep transition-colors duration-300 ease-out': isCompletedNotCurrent,
'bg-secondary text-secondary-content notCurrentStep transition-colors duration-300 ease-out delay-[300ms]': isPendingNotCurrent,
});
return { outerClasses, innerClasses };
});
/**
* Step number visibility classes
* @returns {string} Tailwind classes with fade animation
* @remarks
* - Hidden when completed
* - 350ms fade-in delay for smooth transitions
* @internal
*/
stepNumberClasses = computed(() => {
const isCompleted = this.status() === 'completed';
return cn({
'hidden opacity-0': isCompleted,
'animate-fade-in animate-duration-300 delay-[350ms] opacity-100': !isCompleted,
});
});
/**
* Completion icon visibility classes
* @returns {string} Tailwind classes with fade animation
* @remarks
* - Only visible when completed
* - 350ms fade-in delay for smooth transition
* @internal
*/
stepIconClasses = computed(() => {
const isCompleted = this.status() === 'completed';
return cn({
'animate-fade-in animate-duration-300 delay-[350ms] opacity-100': isCompleted,
'hidden opacity-0': !isCompleted,
});
});
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardStepComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.0", type: WizardStepComponent, isStandalone: true, selector: "st-wizard-step", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, status: { classPropertyName: "status", publicName: "status", isSignal: true, isRequired: true, transformFunction: null }, stepIndex: { classPropertyName: "stepIndex", publicName: "stepIndex", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<div [class]=\"stepClasses().outerClasses\">\n\t<div [class]=\"stepClasses().innerClasses\">\n\t\t<div [class]=\"stepNumberClasses()\">\n\t\t\t@let iconVar = icon();\n\t\t\t@if (iconVar) {\n\t\t\t\t<st-icon [icon]=\"iconVar\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t\t} @else {\n\t\t\t\t<span typography [tyVariant]=\"'body'\" [tyColor]=\"'base'\" [tyFontWeight]=\"'semibold'\">\n\t\t\t\t\t{{ stepIndex() + 1 }}\n\t\t\t\t</span>\n\t\t\t}\n\t\t</div>\n\t\t<div [class]=\"stepIconClasses()\">\n\t\t\t<st-icon [icon]=\"iconCheck\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t</div>\n\t</div>\n</div>\n", dependencies: [{ kind: "directive", type: TypographyDirective, selector: "[typography]", inputs: ["tyVariant", "tyColor", "tyFontWeight", "tyTextOverflow"] }, { kind: "component", type: IconComponent, selector: "st-icon", inputs: ["color", "size", "icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardStepComponent, decorators: [{
type: Component,
args: [{ selector: 'st-wizard-step', imports: [TypographyDirective, IconComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"stepClasses().outerClasses\">\n\t<div [class]=\"stepClasses().innerClasses\">\n\t\t<div [class]=\"stepNumberClasses()\">\n\t\t\t@let iconVar = icon();\n\t\t\t@if (iconVar) {\n\t\t\t\t<st-icon [icon]=\"iconVar\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t\t} @else {\n\t\t\t\t<span typography [tyVariant]=\"'body'\" [tyColor]=\"'base'\" [tyFontWeight]=\"'semibold'\">\n\t\t\t\t\t{{ stepIndex() + 1 }}\n\t\t\t\t</span>\n\t\t\t}\n\t\t</div>\n\t\t<div [class]=\"stepIconClasses()\">\n\t\t\t<st-icon [icon]=\"iconCheck\" color=\"inherit\" size=\"md\"></st-icon>\n\t\t</div>\n\t</div>\n</div>\n" }]
}] });
/**
* A component that visualizes the connection between wizard steps with animated progress indicators.
*
* @remarks
* Handles both horizontal and vertical layouts with status-dependent animations. Manages three segments:
* - Left connector (before the step)
* - Center indicator (current step marker)
* - Right connector (after the step)
*
* @example
* ```html
* <!-- Horizontal sub-step -->
* <st-wizard-sub-step
* [stepIndex]="1"
* [stepStatus]="'completed'"
* ></st-wizard-sub-step>
*
* <!-- Vertical sub-step -->
* <st-wizard-sub-step
* variant="vertical"
* [stepIndex]="2"
* [stepStatus]="'in progress'"
* ></st-wizard-sub-step>
* ```
*/
class WizardSubStepComponent {
/**
* Layout direction for the sub-step connectors
* @default 'horizontal'
*/
variant = input('horizontal');
/** @internal Injected wizard state service */
wizardService = inject(WizardService);
/**
* Index of the parent step in the wizard sequence
* @remarks Required for position calculation
*/
stepIndex = input.required();
/**
* Current status of the associated wizard step
* @remarks Determines visual state and animations
*/
stepStatus = input.required();
/**
* Checks if this sub-step's index matches the current active step
* @returns {boolean} True if this is the active step
* @internal
*/
isCurrentStep = computed(() => this.wizardService.currentStepIndex() === this.stepIndex());
/**
* Computed classes for horizontal left connector segment
* @returns {string} Tailwind classes with animated width transition
* @internal
*/
horizontalLeftClasses = computed(() => {
const isCompleted = this.stepStatus() === 'completed';
const isInProgress = this.stepStatus() === 'in progress';
const afterWidthClass = isCompleted || (this.isCurrentStep() && isInProgress) ? 'after:w-full' : 'after:w-0';
return cn('h-[2px] w-full bg-secondary relative', 'after:absolute after:left-0 after:bottom-0 after:bg-primary after:h-[2px]', 'after:transition-[width] after:duration-300 after:ease-out', afterWidthClass);
});
/**
* Computed classes for horizontal center indicator
* @returns {string} Tailwind classes with color transition delays
* @internal
*/
horizontalCenterClasses = computed(() => {
const isPrimaryBg = (this.isCurrentStep() && this.stepStatus() !== 'pending') || (!this.isCurrentStep() && this.stepStatus() === 'completed');
return cn('h-3 min-h-3 w-3 min-w-3 rounded-full', 'transition-colors duration-300 ease-out', isPrimaryBg ? 'bg-primary' : 'bg-secondary', isPrimaryBg && !this.isCurrentStep() ? '' : 'delay-300');
});
/**
* Computed classes for horizontal right connector segment
* @returns {string} Tailwind classes with completion-based width
* @internal
*/
horizontalRightClasses = computed(() => {
const isCompleted = this.stepStatus() === 'completed';
const afterWidthClass = isCompleted ? 'after:w-full' : 'after:w-0';
return cn('h-[2px] w-full bg-secondary relative', 'after:absolute after:left-0 after:bottom-0 after:bg-primary after:h-[2px]', 'after:transition-[width] after:duration-300 after:ease-out', afterWidthClass);
});
/**
* Computed classes for vertical left connector segment
* @returns {string} Tailwind classes with animated height transition
* @internal
*/
verticalLeftClasses = computed(() => {
const isCompleted = this.stepStatus() === 'completed';
const isInProgress = this.stepStatus() === 'in progress';
const afterHeightClass = isCompleted || (this.isCurrentStep() && isInProgress) ? 'after:h-full' : 'after:h-0';
return cn('w-[2px] h-full bg-secondary relative rotate-180', 'after:absolute after:left-0 after:bottom-0 after:bg-primary after:w-[2px]', 'after:transition-[height] after:duration-300 after:ease-out', afterHeightClass);
});
/**
* Computed classes for vertical center indicator
* @returns {string} Tailwind classes with color transition logic
* @internal
*/
verticalCenterClasses = computed(() => {
const isPrimaryBg = (this.isCurrentStep() && this.stepStatus() !== 'pending') || (!this.isCurrentStep() && this.stepStatus() === 'completed');
return cn('h-3 min-h-3 w-3 min-w-3 rounded-full', 'transition-colors duration-300 ease-out', isPrimaryBg ? 'bg-primary' : 'bg-secondary', isPrimaryBg && !this.isCurrentStep() ? '' : 'delay-300');
});
/**
* Computed classes for vertical right connector segment
* @returns {string} Tailwind classes with completion-based height
* @internal
*/
verticalRightClasses = computed(() => {
const isCompleted = this.stepStatus() === 'completed';
const afterHeightClass = isCompleted ? 'after:h-full' : 'after:h-0';
return cn('w-[2px] h-full bg-secondary relative rotate-180', 'after:absolute after:left-0 after:bottom-0 after:bg-primary after:w-[2px]', 'after:transition-[height] after:duration-300 after:ease-out', afterHeightClass);
});
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardSubStepComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.0", type: WizardSubStepComponent, isStandalone: true, selector: "st-wizard-sub-step", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, stepIndex: { classPropertyName: "stepIndex", publicName: "stepIndex", isSignal: true, isRequired: true, transformFunction: null }, stepStatus: { classPropertyName: "stepStatus", publicName: "stepStatus", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@if (variant() === 'horizontal') {\n\t<div class=\"flex min-w-[max(100%,80px)] flex-1 -translate-y-[18px] items-center\">\n\t\t<div [class]=\"horizontalLeftClasses()\"></div>\n\t\t<div [class]=\"horizontalCenterClasses()\"></div>\n\t\t<div [class]=\"horizontalRightClasses()\"></div>\n\t</div>\n} @else {\n\t<div class=\"flex h-20 min-h-20 w-fit translate-x-[18px] flex-col items-center\">\n\t\t<div [class]=\"verticalLeftClasses()\"></div>\n\t\t<div [class]=\"verticalCenterClasses()\"></div>\n\t\t<div [class]=\"verticalRightClasses()\"></div>\n\t</div>\n}\n" });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardSubStepComponent, decorators: [{
type: Component,
args: [{ selector: 'st-wizard-sub-step', imports: [], template: "@if (variant() === 'horizontal') {\n\t<div class=\"flex min-w-[max(100%,80px)] flex-1 -translate-y-[18px] items-center\">\n\t\t<div [class]=\"horizontalLeftClasses()\"></div>\n\t\t<div [class]=\"horizontalCenterClasses()\"></div>\n\t\t<div [class]=\"horizontalRightClasses()\"></div>\n\t</div>\n} @else {\n\t<div class=\"flex h-20 min-h-20 w-fit translate-x-[18px] flex-col items-center\">\n\t\t<div [class]=\"verticalLeftClasses()\"></div>\n\t\t<div [class]=\"verticalCenterClasses()\"></div>\n\t\t<div [class]=\"verticalRightClasses()\"></div>\n\t</div>\n}\n" }]
}] });
/**
* A container component for multi-step workflows with navigation controls and layout management.
*
* @remarks
* Integrates with WizardService for state management and provides template structure for wizard steps.
* Supports both horizontal and vertical layouts with customizable navigation controls.
*
* @example
* ```html
* <!-- Basic horizontal wizard -->
* <st-wizard>
* <st-wizard-content [stepIndex]="0" name="Step 1" [isValid]="true">
* <!-- Step content -->
* </st-wizard-content>
* <st-wizard-content [stepIndex]="1" name="Step 2">
* <!-- Step content -->
* </st-wizard-content>
* </st-wizard>
*
* <!-- Vertical wizard with external controls -->
* <st-wizard variant="vertical" [showControls]="false">
* <!-- Step contents -->
* </st-wizard>
* <div class="controls">
* <st-button (click)="handlePrevious()">Previous</st-button>
* <st-button (click)="handleNext()">Next</st-button>
* </div>
* ```
*/
class WizardWrapperComponent {
/**
* Injected wizard state management service instance
* @internal
*/
wizardService = inject(WizardService);
/**
* Controls the layout direction of the wizard steps
* @default 'horizontal'
* @example
* <st-wizard variant="vertical">...</st-wizard>
*/
variant = input('horizontal');
/**
* Add a card style to the wizard
* @default false
* @example
* <st-wizard [card]="true">...</st-wizard>
*/
card = input(false);
/**
* Query list of contained wizard content components
* @internal
*/
contents = contentChildren(WizardContentComponent);
/**
* Controls visibility of built-in navigation controls
* @default true
* @example
* <st-wizard [showControls]="false">...</st-wizard>
*/
showControls = input(true);
/**
* Event emitted when the back button is clicked
* @example
* <st-wizard (back)="handleCancel()">...</st-wizard>
*/
back = output();
/**
* Event emitted when navigating to the previous step
* @example
* <st-wizard (previous)="logStepChange('previous')">...</st-wizard>
*/
previous = output();
/**
* Event emitted when navigating to the next valid step
* @example
* <st-wizard (next)="logStepChange('next')">...</st-wizard>
*/
next = output();
/**
* Event emitted when all steps are completed
* @example
* <st-wizard (complete)="showCompletionModal()">...</st-wizard>
*/
complete = output();
/**
* Controls visibility of the loading spinner for completition button
* @default false
* @example
* <st-wizard [loading]="true">...</st-wizard>
*/
loading = input(false);
// Icon definitions
/** @internal Material design chevron left icon */
iconChevronLeft = matChevronLeftOutline;
/** @internal Material design chevron right icon */
iconChevronRight = matChevronRightOutline;
/** @internal Material design return arrow icon */
iconReturn = matKeyboardReturnOutline;
/** @internal Material design save/floppy disk icon */
iconSave = matSaveOutline;
/**
* Handles back navigation and emits onBack event
* @emits back
* @example
* // Template
* <button (click)="handleBack()">Cancel</button>
*
* // Component
* handleBack() {
* this.back.emit();
* }
*/
handleBack() {
this.back.emit();
}
/**
* Navigates to previous step and emits previous event
* @emits previous
* @example
* // Manually trigger previous step
* previousStep() {
* this.wizardService.previousStep();
* this.previous.emit();
* }
*/
handlePrevious() {
this.wizardService.previousStep();
this.previous.emit();
}
/**
* Navigates to next valid step and emits next event
* @emits next
* @example
* // Custom next step handler
* handleNext() {
* if (form.valid) {
* this.wizardService.nextStep();
* this.next.emit();
* }
* }
*/
handleNext() {
this.wizardService.nextStep();
this.next.emit();
}
/**
* Completes wizard flow and emits complete event
* @emits complete
* @example
* // Final step handler
* handleComplete() {
* if (allStepsValid) {
* this.complete.emit();
* }
* }
*/
handleComplete() {
this.complete.emit();
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardWrapperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.0", type: WizardWrapperComponent, isStandalone: true, selector: "st-wizard", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, card: { classPropertyName: "card", publicName: "card", isSignal: true, isRequired: false, transformFunction: null }, showControls: { classPropertyName: "showControls", publicName: "showControls", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { back: "back", previous: "previous", next: "next", complete: "complete" }, queries: [{ propertyName: "contents", predicate: WizardContentComponent, isSignal: true }], ngImport: i0, template: "@let contentsVar = contents();\n@let varinatVar = variant();\n\n<div\n\t[class]=\"varinatVar === 'horizontal' ? 'flex flex-col gap-6' : 'flex gap-6'\"\n\t[ngClass]=\"{ 'rounded-box bg-base-200 shadow-main p-6': card() && varinatVar === 'horizontal' }\"\n>\n\t<!-- Steps -->\n\t@if (varinatVar === 'horizontal') {\n\t\t<ul class=\"flex gap-4 px-[20%] pt-6\">\n\t\t\t@for (step of wizardService.steps(); track $index) {\n\t\t\t\t<li [ngClass]=\"{ 'flex-1': contentsVar.length - 1 !== $index }\">\n\t\t\t\t\t<div class=\"flex items-center gap-4\">\n\t\t\t\t\t\t<st-wizard-step [icon]=\"step.icon\" [stepIndex]=\"$index\" [status]=\"step.status\"></st-wizard-step>\n\t\t\t\t\t\t@if (contentsVar.length - 1 !== $index) {\n\t\t\t\t\t\t\t<div class=\"flex flex-1 flex-col justify-center\">\n\t\t\t\t\t\t\t\t<div class=\"flex -translate-y-6 justify-center\">\n\t\t\t\t\t\t\t\t\t<st-wizard-marker [status]=\"step.status\"></st-wizard-marker>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<st-wizard-sub-step [stepIndex]=\"$index\" [stepStatus]=\"step.status\"></st-wizard-sub-step>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"mt-1 w-[50px]\">\n\t\t\t\t\t\t<div class=\"relative flex max-w-fit flex-col items-center\">\n\t\t\t\t\t\t\t<div class=\"min-w-max\">\n\t\t\t\t\t\t\t\t<span typography [tyVariant]=\"'body-sm'\" [tyColor]=\"'base'\" [tyFontWeight]=\"'medium'\">{{ step.label }}</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"text-secondary relative -top-1 min-w-max\">\n\t\t\t\t\t\t\t\t<span typography [tyVariant]=\"'body-xs'\" [tyColor]=\"'inherit'\" [tyFontWeight]=\"'normal'\">\n\t\t\t\t\t\t\t\t\t{{ 'sdk.wizard.wizardWrapper.step' | translate: { index: $index + 1 } }}</span\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t}\n\t\t</ul>\n\t} @else {\n\t\t<ul class=\"grid h-min max-h-min gap-4\" [ngClass]=\"{ 'rounded-box bg-base-200 shadow-main p-6': card() }\">\n\t\t\t@for (step of wizardService.steps(); track $index) {\n\t\t\t\t<li>\n\t\t\t\t\t<!-- step pogress -->\n\t\t\t\t\t<div class=\"grid grid-rows-[min-content_min-content] gap-4\">\n\t\t\t\t\t\t<div class=\"flex items-center gap-3\">\n\t\t\t\t\t\t\t<st-wizard-step [icon]=\"step.icon\" [stepIndex]=\"$index\" [status]=\"step.status\"></st-wizard-step>\n\t\t\t\t\t\t\t<!-- step info -->\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<div class=\"relative flex max-w-fit flex-col\">\n\t\t\t\t\t\t\t\t\t<div class=\"min-w-max\">\n\t\t\t\t\t\t\t\t\t\t<span typography [tyVariant]=\"'body-sm'\" [tyColor]=\"'base'\" [tyFontWeight]=\"'medium'\">{{ step.label }}</span>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t\t<div class=\"text-neutral relative -top-1 min-w-max\">\n\t\t\t\t\t\t\t\t\t\t<span typography [tyVariant]=\"'body-xs'\" [tyColor]=\"'inherit'\" [tyFontWeight]=\"'normal'\">\n\t\t\t\t\t\t\t\t\t\t\t{{ 'sdk.wizard.wizardWrapper.step' | translate: { index: $index + 1 } }}</span\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t\t@if (contentsVar.length - 1 !== $index) {\n\t\t\t\t\t\t\t<div class=\"flex flex-col justify-center\">\n\t\t\t\t\t\t\t\t<st-wizard-sub-step variant=\"vertical\" [stepIndex]=\"$index\" [stepStatus]=\"step.status\"></st-wizard-sub-step>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t}\n\t\t</ul>\n\t}\n\n\t<div class=\"flex flex-1 flex-col gap-6\" [ngClass]=\"{ 'rounded-box bg-base-200 shadow-main p-6': card() && varinatVar === 'vertical' }\">\n\t\t<!-- Content -->\n\t\t<div>\n\t\t\t<ng-content></ng-content>\n\t\t</div>\n\n\t\t<!-- Actions -->\n\t\t@if (this.showControls()) {\n\t\t\t<div class=\"flex items-center justify-end gap-3\">\n\t\t\t\t@if (wizardService.isCurrentStepFirst()) {\n\t\t\t\t\t<st-button variant=\"secondary\" [icon]=\"iconReturn\" (click)=\"handleBack()\">{{ 'sdk.wizard.wizardWrapper.back' | translate }}</st-button>\n\t\t\t\t} @else {\n\t\t\t\t\t<st-button [icon]=\"iconChevronLeft\" variant=\"secondary\" (click)=\"handlePrevious()\">{{\n\t\t\t\t\t\t'sdk.wizard.wizardWrapper.previous' | translate\n\t\t\t\t\t}}</st-button>\n\t\t\t\t}\n\t\t\t\t@if (wizardService.isCurrentStepLast()) {\n\t\t\t\t\t<st-button\n\t\t\t\t\t\t[disabled]=\"!wizardService.areAllStepsValid()\"\n\t\t\t\t\t\tvariant=\"primary\"\n\t\t\t\t\t\t(click)=\"handleComplete()\"\n\t\t\t\t\t\t[disabled]=\"loading()\"\n\t\t\t\t\t\t[loader]=\"loading()\"\n\t\t\t\t\t>\n\t\t\t\t\t\t@if (!loading()) {\n\t\t\t\t\t\t\t<st-icon [icon]=\"iconSave\"></st-icon>\n\n\t\t\t\t\t\t\t{{ 'sdk.wizard.wizardWrapper.end' | translate }}\n\t\t\t\t\t\t}\n\t\t\t\t\t</st-button>\n\t\t\t\t} @else {\n\t\t\t\t\t<st-button [icon]=\"iconChevronRight\" iconPosition=\"right\" [disabled]=\"!wizardService.currentStep().isValid\" (click)=\"handleNext()\">{{\n\t\t\t\t\t\t'sdk.wizard.wizardWrapper.next' | translate\n\t\t\t\t\t}}</st-button>\n\t\t\t\t}\n\t\t\t</div>\n\t\t} @else {\n\t\t\t<ng-content select=\"st-wizard-actions\"></ng-content>\n\t\t}\n\t</div>\n</div>\n", dependencies: [{ kind: "component", type: WizardStepComponent, selector: "st-wizard-step", inputs: ["icon", "status", "stepIndex"] }, { kind: "component", type: ButtonComponent, selector: "st-button", inputs: ["variant", "ghost", "outline", "link", "soft", "dash", "wide", "circle", "square", "glass", "block", "loader", "size", "shadow", "focusable", "icon", "iconPosition", "type", "disabled"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: TypographyDirective, selector: "[typography]", inputs: ["tyVariant", "tyColor", "tyFontWeight", "tyTextOverflow"] }, { kind: "component", type: WizardMarkerComponent, selector: "st-wizard-marker", inputs: ["status"] }, { kind: "component", type: WizardSubStepComponent, selector: "st-wizard-sub-step", inputs: ["variant", "stepIndex", "stepStatus"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: IconComponent, selector: "st-icon", inputs: ["color", "size", "icon"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: WizardWrapperComponent, decorators: [{
type: Component,
args: [{ selector: 'st-wizard', imports: [
WizardStepComponent,
ButtonComponent,
NgClass,
TypographyDirective,
WizardMarkerComponent,
WizardSubStepComponent,
TranslatePipe,
IconComponent,
], template: "@let contentsVar = contents();\n@let varinatVar = variant();\n\n<div\n\t[class]=\"varinatVar === 'horizontal' ? 'flex flex-col gap-6' : 'flex gap-6'\"\n\t[ngClass]=\"{ 'rounded-box bg-base-200 shadow-main p-6': card() && varinatVar === 'horizontal' }\"\n>\n\t<!-- Steps -->\n\t@if (varinatVar === 'horizontal') {\n\t\t<ul class=\"flex gap-4 px-[20%] pt-6\">\n\t\t\t@for (step of wizardService.steps(); track $index) {\n\t\t\t\t<li [ngClass]=\"{ 'flex-1': contentsVar.length - 1 !== $index }\">\n\t\t\t\t\t<div class=\"flex items-center gap-4\">\n\t\t\t\t\t\t<st-wizard-step [icon]=\"step.icon\" [stepIndex]=\"$index\" [status]=\"step.status\"></st-wizard-step>\n\t\t\t\t\t\t@if (contentsVar.length - 1 !== $index) {\n\t\t\t\t\t\t\t<div class=\"flex flex-1 flex-col justify-center\">\n\t\t\t\t\t\t\t\t<div class=\"flex -translate-y-6 justify-center\">\n\t\t\t\t\t\t\t\t\t<st-wizard-marker [status]=\"step.status\"></st-wizard-marker>\n\t\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t\t<st-wizard-sub-step [stepIndex]=\"$index\" [stepStatus]=\"step.status\"></st-wizard-sub-step>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t\t<div class=\"mt-1 w-[50px]\">\n\t\t\t\t\t\t<div class=\"relative flex max-w-fit flex-col items-center\">\n\t\t\t\t\t\t\t<div class=\"min-w-max\">\n\t\t\t\t\t\t\t\t<span typography [tyVariant]=\"'body-sm'\" [tyColor]=\"'base'\" [tyFontWeight]=\"'medium'\">{{ step.label }}</span>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t\t<div class=\"text-secondary relative -top-1 min-w-max\">\n\t\t\t\t\t\t\t\t<span typography [tyVariant]=\"'body-xs'\" [tyColor]=\"'inherit'\" [tyFontWeight]=\"'normal'\">\n\t\t\t\t\t\t\t\t\t{{ 'sdk.wizard.wizardWrapper.step' | translate: { index: $index + 1 } }}</span\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</div>\n\t\t\t\t</li>\n\t\t\t}\n\t\t</ul>\n\t} @else {\n\t\t<ul class=\"grid h-min max-h-min gap-4\" [ngClass]=\"{ 'rounded-box bg-base-200 shadow-main p-6': card() }\">\n\t\t\t@for (step of wizardService.steps(); track $index) {\n\t\t\t\t<li>\n\t\t\t\t\t<!-- step pogress -->\n\t\t\t\t\t<div class=\"grid grid-rows-[min-content_min-content] gap-4\">\n\t\t\t\t\t\t<div class=\"flex items-center gap-3\">\n\t\t\t\t\t\t\t<st-wizard-step [icon]=\"step.icon\" [stepIndex]=\"$index\" [status]=\"step.status\"></st-wizard-step>\n\t\t\t\t\t\t\t<!-- step info -->\n\t\t\t\t\t\t\t<div>\n\t\t\t\t\t\t\t\t<div class=\"relative flex max-w-fit flex-col\">\n\t\t\t\t\t\t\t\t\t<div class=\"min-w-max\">\n\t\t\t\t\t\t\