@truenas/ui-components 0.3.16 → 0.3.17

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.
@@ -15737,10 +15737,12 @@ class TnStepComponent {
15737
15737
  optional = input(false, ...(ngDevMode ? [{ debugName: "optional" }] : []));
15738
15738
  completed = input(false, ...(ngDevMode ? [{ debugName: "completed" }] : []));
15739
15739
  hasError = input(false, ...(ngDevMode ? [{ debugName: "hasError" }] : []));
15740
+ /** Message shown beneath the step label while the step is in an error state. */
15741
+ errorMessage = input(undefined, ...(ngDevMode ? [{ debugName: "errorMessage" }] : []));
15740
15742
  data = input(null, ...(ngDevMode ? [{ debugName: "data" }] : []));
15741
15743
  content = viewChild.required('content');
15742
15744
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
15743
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.0", type: TnStepComponent, isStandalone: true, selector: "tn-step", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, completed: { classPropertyName: "completed", publicName: "completed", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: `
15745
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.1.0", type: TnStepComponent, isStandalone: true, selector: "tn-step", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, optional: { classPropertyName: "optional", publicName: "optional", isSignal: true, isRequired: false, transformFunction: null }, completed: { classPropertyName: "completed", publicName: "completed", isSignal: true, isRequired: false, transformFunction: null }, hasError: { classPropertyName: "hasError", publicName: "hasError", isSignal: true, isRequired: false, transformFunction: null }, errorMessage: { classPropertyName: "errorMessage", publicName: "errorMessage", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: `
15744
15746
  <ng-template #content>
15745
15747
  <ng-content />
15746
15748
  </ng-template>
@@ -15757,7 +15759,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
15757
15759
  `,
15758
15760
  standalone: true
15759
15761
  }]
15760
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], optional: [{ type: i0.Input, args: [{ isSignal: true, alias: "optional", required: false }] }], completed: [{ type: i0.Input, args: [{ isSignal: true, alias: "completed", required: false }] }], hasError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasError", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], content: [{ type: i0.ViewChild, args: ['content', { isSignal: true }] }] } });
15762
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], optional: [{ type: i0.Input, args: [{ isSignal: true, alias: "optional", required: false }] }], completed: [{ type: i0.Input, args: [{ isSignal: true, alias: "completed", required: false }] }], hasError: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasError", required: false }] }], errorMessage: [{ type: i0.Input, args: [{ isSignal: true, alias: "errorMessage", required: false }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }], content: [{ type: i0.ViewChild, args: ['content', { isSignal: true }] }] } });
15761
15763
 
15762
15764
  class TnStepperComponent {
15763
15765
  orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
@@ -15771,8 +15773,15 @@ class TnStepperComponent {
15771
15773
  selectionChange = output();
15772
15774
  completed = output();
15773
15775
  steps = contentChildren(TnStepComponent, { ...(ngDevMode ? { debugName: "steps" } : {}), descendants: true });
15774
- cdr = inject(ChangeDetectorRef);
15776
+ // Highest step index the user has navigated to. Used to reveal the "edit" (pencil)
15777
+ // affordance only on steps that have actually been visited — a step that is valid by
15778
+ // default but never reached stays a plain number.
15779
+ maxReachedIndex = signal(0, ...(ngDevMode ? [{ debugName: "maxReachedIndex" }] : []));
15775
15780
  constructor() {
15781
+ effect(() => {
15782
+ const index = this.selectedIndex();
15783
+ this.maxReachedIndex.update((max) => Math.max(max, index));
15784
+ });
15776
15785
  // Effect to check if all steps are completed
15777
15786
  effect(() => {
15778
15787
  // Trigger on any step completion change
@@ -15783,8 +15792,8 @@ class TnStepperComponent {
15783
15792
  }
15784
15793
  });
15785
15794
  }
15786
- onWindowResize(_event) {
15787
- this.cdr.detectChanges();
15795
+ onWindowResize() {
15796
+ this.isWideScreen.set(window.innerWidth > 768);
15788
15797
  }
15789
15798
  _getStepData() {
15790
15799
  return this.steps().map(step => ({
@@ -15793,10 +15802,33 @@ class TnStepperComponent {
15793
15802
  data: step.data()
15794
15803
  }));
15795
15804
  }
15796
- isWideScreen = computed(() => {
15797
- // Note: This will only update on window resize due to ChangeDetectorRef trigger
15798
- return window.innerWidth > 768;
15799
- }, ...(ngDevMode ? [{ debugName: "isWideScreen" }] : []));
15805
+ // Tracks whether the viewport is wide enough for the horizontal layout. A signal
15806
+ // (not a computed over `window.innerWidth`, which is non-reactive and would freeze on
15807
+ // first read) so `onWindowResize` can `.set()` it and `auto` orientation re-evaluates.
15808
+ isWideScreen = signal(window.innerWidth > 768, ...(ngDevMode ? [{ debugName: "isWideScreen" }] : []));
15809
+ // Vertical mode lays the active step's content out inline beneath its header
15810
+ // (mat-vertical-stepper style), so it fits narrow containers such as side panels.
15811
+ isVertical = computed(() => {
15812
+ return this.orientation() === 'vertical' || (this.orientation() === 'auto' && !this.isWideScreen());
15813
+ }, ...(ngDevMode ? [{ debugName: "isVertical" }] : []));
15814
+ // Per-index "editable" flags. A step shows the "edit" (pencil) icon once it has been
15815
+ // visited and is valid (completed) but isn't the current step — signalling the user can
15816
+ // go back and change it. Computed (not a per-call method) so it's evaluated once per
15817
+ // change-detection cycle and cheaply indexed in the template, even as step counts grow.
15818
+ stepEditable = computed(() => {
15819
+ const max = this.maxReachedIndex();
15820
+ const current = this.selectedIndex();
15821
+ return this.steps().map((step, index) => !!step.completed() && index <= max && index !== current);
15822
+ }, ...(ngDevMode ? [{ debugName: "stepEditable" }] : []));
15823
+ // Per-index "gated" flags for linear mode: a step is gated (not yet selectable) while
15824
+ // any prior step is incomplete. Memoized so the header's aria-disabled / tabindex
15825
+ // bindings don't re-run canSelectStep() for every step on each change-detection cycle.
15826
+ stepGated = computed(() => {
15827
+ if (!this.linear()) {
15828
+ return this.steps().map(() => false);
15829
+ }
15830
+ return this.steps().map((_step, index) => !this.canSelectStep(index));
15831
+ }, ...(ngDevMode ? [{ debugName: "stepGated" }] : []));
15800
15832
  selectStep(index) {
15801
15833
  if (!this.linear() || this.canSelectStep(index)) {
15802
15834
  const previousIndex = this.selectedIndex();
@@ -15835,7 +15867,7 @@ class TnStepperComponent {
15835
15867
  return index;
15836
15868
  }
15837
15869
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
15838
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnStepperComponent, isStandalone: true, selector: "tn-stepper", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, selectedIndex: { classPropertyName: "selectedIndex", publicName: "selectedIndex", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedIndex: "selectedIndexChange", selectionChange: "selectionChange", completed: "completed" }, host: { listeners: { "window:resize": "onWindowResize($event)" } }, queries: [{ propertyName: "steps", predicate: TnStepComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tn-stepper\"\n tnTestIdType=\"stepper\"\n [class.tn-stepper--horizontal]=\"orientation() === 'horizontal' || (orientation() === 'auto' && isWideScreen())\"\n [class.tn-stepper--vertical]=\"orientation() === 'vertical' || (orientation() === 'auto' && !isWideScreen())\"\n [tnTestId]=\"testId()\">\n\n <!-- Step Headers -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <div class=\"tn-stepper__step-header\"\n tabindex=\"0\"\n role=\"button\"\n [class.tn-stepper__step-header--active]=\"selectedIndex() === i\"\n [class.tn-stepper__step-header--completed]=\"step.completed()\"\n [class.tn-stepper__step-header--error]=\"step.hasError()\"\n [class.tn-stepper__step-header--optional]=\"step.optional()\"\n (click)=\"selectStep(i)\"\n (keydown.enter)=\"selectStep(i)\"\n (keydown.space)=\"selectStep(i)\">\n\n <!-- Step Number/Icon -->\n <div class=\"tn-stepper__step-indicator\">\n @if (step.completed() && !step.hasError()) {\n <span class=\"tn-stepper__step-check\">\u2713</span>\n }\n @if (step.hasError()) {\n <span class=\"tn-stepper__step-error\">!</span>\n }\n @if (!step.completed() && !step.hasError()) {\n @if (step.icon()) {\n <span class=\"tn-stepper__step-icon\">{{ step.icon() }}</span>\n } @else {\n <span class=\"tn-stepper__step-number\">{{ i + 1 }}</span>\n }\n }\n </div>\n\n <!-- Step Label -->\n <div class=\"tn-stepper__step-label\">\n <div class=\"tn-stepper__step-title\" [innerHTML]=\"step.label() | tnLabelMarkup\"></div>\n @if (step.optional()) {\n <span class=\"tn-stepper__step-subtitle\">Optional</span>\n }\n </div>\n </div>\n\n <!-- Connector Line (except for last step) -->\n @if (i < steps().length - 1) {\n <div class=\"tn-stepper__connector\"></div>\n }\n }\n </div>\n\n <!-- Step Content -->\n <div class=\"tn-stepper__content\">\n @for (step of steps(); track $index; let i = $index) {\n @if (selectedIndex() === i) {\n <div class=\"tn-stepper__step-content\"\n [@stepTransition]=\"selectedIndex()\">\n <ng-container *ngTemplateOutlet=\"step.content()\" />\n </div>\n }\n }\n </div>\n</div>", styles: [".tn-stepper{display:flex;font-family:inherit;--step-diameter: 48px;--step-diameter-sm: 32px;--step-padding: 12px}.tn-stepper--horizontal{flex-direction:column}.tn-stepper--horizontal .tn-stepper__header{display:flex;justify-content:center;margin-bottom:32px;padding:0 16px}.tn-stepper--horizontal .tn-stepper__step-header{display:flex;flex-direction:column;align-items:center;text-align:center;cursor:pointer;transition:all .2s ease-in-out}.tn-stepper--horizontal .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--horizontal .tn-stepper__connector{flex:1;height:2px;background:var(--tn-lines, #e5e7eb);margin:0 16px;position:relative;top:calc(var(--step-diameter) / 2)}.tn-stepper--vertical{flex-direction:row}.tn-stepper--vertical .tn-stepper__header{display:flex;flex-direction:column;width:280px;padding:16px;border-right:1px solid var(--tn-lines, #e5e7eb)}.tn-stepper--vertical .tn-stepper__step-header{display:flex;flex-direction:row;align-items:center;text-align:left;cursor:pointer;transition:all .2s ease-in-out;padding:var(--step-padding);border-radius:8px;margin-bottom:8px}.tn-stepper--vertical .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin-left:12px;margin-top:0}.tn-stepper--vertical .tn-stepper__connector{width:2px;height:24px;background:var(--tn-lines, #e5e7eb);position:relative;left:calc(var(--step-diameter) / 2 + var(--step-padding));margin-bottom:8px}.tn-stepper--vertical .tn-stepper__content{flex:1;padding:16px}.tn-stepper__step-indicator{display:flex;align-items:center;justify-content:center;width:var(--step-diameter);height:var(--step-diameter);border-radius:50%;background:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-alt-fg1, #495057);font-weight:400;font-size:14px;transition:all .2s ease-in-out;position:relative;transform:scale(.65)}.tn-stepper__step-number{font-weight:400}.tn-stepper__step-label{margin-top:8px}.tn-stepper__step-title ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-stepper__step-title{display:block;font-weight:400;font-size:14px;color:var(--tn-fg1, #000000);line-height:1.2}.tn-stepper__step-subtitle{display:block;font-size:12px;color:var(--tn-fg2, #6c757d);margin-top:2px}.tn-stepper__step-header--active .tn-stepper__step-indicator{background:var(--tn-primary, #007bff);color:var(--tn-primary-txt, #ffffff);transform:scale(1)}.tn-stepper__step-header--active .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--completed .tn-stepper__step-indicator{background:var(--tn-green, #28a745);color:#fff}.tn-stepper__step-header--completed .tn-stepper__step-check{font-size:1rem;font-weight:700}.tn-stepper__step-header--error .tn-stepper__step-indicator{background:var(--tn-red, #dc3545);color:#fff}.tn-stepper__step-header--error .tn-stepper__step-error{font-size:18px;font-weight:700}.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg1, #000000)}.tn-stepper__step-header--active.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--optional .tn-stepper__step-indicator{border:2px dashed var(--tn-lines, #e5e7eb);background:transparent}.tn-stepper--horizontal .tn-stepper__step-header--completed+.tn-stepper__connector{background:var(--tn-green, #28a745)}.tn-stepper--horizontal .tn-stepper__step-header--completed+.tn-stepper__connector:after{content:\"\";position:absolute;top:0;left:0;right:0;height:100%;background:var(--tn-green, #28a745);animation:progressFill .3s ease-in-out}.tn-stepper--vertical .tn-stepper__step-header--completed+.tn-stepper__connector{background:var(--tn-green, #28a745)}.tn-stepper__content{min-height:200px}.tn-stepper__step-content{padding:16px;background:var(--tn-bg1, #ffffff);border-radius:8px;border:1px solid var(--tn-lines, #e5e7eb)}@keyframes progressFill{0%{width:0}to{width:100%}}.tn-stepper__step-header:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-stepper__step-header:focus:not(:focus-visible){outline:none}@media(max-width:780px){.tn-stepper--vertical .tn-stepper__header{width:180px;border-right:none;border-bottom:1px solid var(--tn-lines, #e5e7eb);padding:16px 0}.tn-stepper--vertical .tn-stepper__step-header{flex-direction:column;align-items:center;text-align:center;min-width:80px;padding:8px 4px}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin-left:0;margin-top:8px}.tn-stepper--vertical .tn-stepper__connector{display:none}}@media(max-width:780px){.tn-stepper .tn-stepper__step-label{display:none}.tn-stepper .tn-stepper__step-indicator{width:var(--step-diameter-sm);height:var(--step-diameter-sm);font-size:12px}.tn-stepper--horizontal .tn-stepper__header{padding:0 8px}.tn-stepper--horizontal .tn-stepper__connector{top:calc(var(--step-diameter-sm) / 2);margin:0 8px}.tn-stepper--vertical .tn-stepper__header{width:60px}.tn-stepper--vertical .tn-stepper__step-header{padding:4px;margin-bottom:4px}.tn-stepper--vertical .tn-stepper__connector{left:calc(var(--step-diameter-sm) / 2 + 4px);height:16px;margin-bottom:4px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }], animations: [
15870
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: TnStepperComponent, isStandalone: true, selector: "tn-stepper", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, linear: { classPropertyName: "linear", publicName: "linear", isSignal: true, isRequired: false, transformFunction: null }, selectedIndex: { classPropertyName: "selectedIndex", publicName: "selectedIndex", isSignal: true, isRequired: false, transformFunction: null }, testId: { classPropertyName: "testId", publicName: "testId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedIndex: "selectedIndexChange", selectionChange: "selectionChange", completed: "completed" }, host: { listeners: { "window:resize": "onWindowResize()" } }, queries: [{ propertyName: "steps", predicate: TnStepComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"tn-stepper\"\n tnTestIdType=\"stepper\"\n [class.tn-stepper--horizontal]=\"!isVertical()\"\n [class.tn-stepper--vertical]=\"isVertical()\"\n [tnTestId]=\"testId()\">\n\n <!-- Shared step header (indicator + label) -->\n <ng-template #stepHeader let-step=\"step\" let-i=\"i\">\n <div class=\"tn-stepper__step-header\"\n role=\"button\"\n [attr.tabindex]=\"stepGated()[i] ? -1 : 0\"\n [attr.aria-current]=\"selectedIndex() === i ? 'step' : null\"\n [attr.aria-disabled]=\"stepGated()[i] ? 'true' : null\"\n [class.tn-stepper__step-header--active]=\"selectedIndex() === i\"\n [class.tn-stepper__step-header--completed]=\"step.completed()\"\n [class.tn-stepper__step-header--error]=\"step.hasError()\"\n [class.tn-stepper__step-header--optional]=\"step.optional()\"\n (click)=\"selectStep(i)\"\n (keydown.enter)=\"selectStep(i)\"\n (keydown.space)=\"$event.preventDefault(); selectStep(i)\">\n\n <!-- Step Number/Icon -->\n <div class=\"tn-stepper__step-indicator\"\n [class.tn-stepper__step-indicator--glyph]=\"step.hasError()\">\n @if (step.hasError()) {\n <tn-icon class=\"tn-stepper__step-error\" name=\"alert\" library=\"mdi\" [attr.aria-hidden]=\"true\" />\n } @else if (stepEditable()[i]) {\n <tn-icon class=\"tn-stepper__step-edit\" name=\"pencil\" library=\"mdi\" [attr.aria-hidden]=\"true\" />\n } @else if (step.icon()) {\n <span class=\"tn-stepper__step-icon\">{{ step.icon() }}</span>\n } @else {\n <span class=\"tn-stepper__step-number\">{{ i + 1 }}</span>\n }\n </div>\n\n <!-- Step Label -->\n <div class=\"tn-stepper__step-label\">\n <div class=\"tn-stepper__step-title\" [innerHTML]=\"step.label() | tnLabelMarkup\"></div>\n @if (step.hasError() && step.errorMessage()) {\n <span class=\"tn-stepper__step-error-message\">{{ step.errorMessage() }}</span>\n } @else if (step.optional()) {\n <span class=\"tn-stepper__step-subtitle\">Optional</span>\n }\n </div>\n </div>\n </ng-template>\n\n @if (isVertical()) {\n <!-- Vertical: content renders inline beneath the active step's header -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <div class=\"tn-stepper__step\" [class.tn-stepper__step--last]=\"i === steps().length - 1\">\n <ng-container *ngTemplateOutlet=\"stepHeader; context: { step, i }\" />\n\n <div class=\"tn-stepper__step-body\">\n @if (selectedIndex() === i) {\n <div class=\"tn-stepper__step-content\" [@stepTransition]=\"selectedIndex()\">\n <ng-container *ngTemplateOutlet=\"step.content()\" />\n </div>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- Horizontal: headers in a row, active content below -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <ng-container *ngTemplateOutlet=\"stepHeader; context: { step, i }\" />\n\n @if (i < steps().length - 1) {\n <div class=\"tn-stepper__connector\"></div>\n }\n }\n </div>\n\n <div class=\"tn-stepper__content\">\n @for (step of steps(); track $index; let i = $index) {\n @if (selectedIndex() === i) {\n <div class=\"tn-stepper__step-content\"\n [@stepTransition]=\"selectedIndex()\">\n <ng-container *ngTemplateOutlet=\"step.content()\" />\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [".tn-stepper{display:flex;font-family:inherit;--step-diameter: 48px;--step-diameter-sm: 32px;--step-padding: 12px;--v-indicator: 32px;--v-gap: 12px}.tn-stepper--horizontal{flex-direction:column}.tn-stepper--horizontal .tn-stepper__header{display:flex;justify-content:center;margin-bottom:32px;padding:0 16px}.tn-stepper--horizontal .tn-stepper__step-header{display:flex;flex-direction:column;align-items:center;text-align:center;cursor:pointer;transition:all .2s ease-in-out}.tn-stepper--horizontal .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--horizontal .tn-stepper__connector{flex:1;height:2px;background:var(--tn-lines, #e5e7eb);margin:0 16px;position:relative;top:calc(var(--step-diameter) / 2)}.tn-stepper--vertical{flex-direction:column}.tn-stepper--vertical .tn-stepper__header,.tn-stepper--vertical .tn-stepper__step{display:flex;flex-direction:column}.tn-stepper--vertical .tn-stepper__step-header{display:flex;flex-direction:row;align-items:center;gap:var(--v-gap);text-align:left;cursor:pointer;padding:8px 0}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin:0}.tn-stepper--vertical .tn-stepper__step-indicator{width:var(--v-indicator);height:var(--v-indicator);min-width:var(--v-indicator);font-size:13px;transform:none}.tn-stepper--vertical .tn-stepper__step-indicator--glyph tn-icon{--tn-icon-size: var(--v-indicator)}.tn-stepper--vertical .tn-stepper__step-header--active .tn-stepper__step-indicator{transform:none}.tn-stepper--vertical .tn-stepper__step-body{margin-left:calc(var(--v-indicator) / 2 - 1px);border-left:2px solid var(--tn-lines, #e5e7eb);padding-left:calc(var(--v-indicator) / 2 + var(--v-gap));padding-bottom:8px;min-height:12px}.tn-stepper--vertical .tn-stepper__step--last .tn-stepper__step-body{border-left-color:transparent;min-height:0}.tn-stepper--vertical .tn-stepper__step-content{padding:4px 0 8px;background:transparent;border:none;border-radius:0}.tn-stepper__step-indicator{display:flex;align-items:center;justify-content:center;width:var(--step-diameter);height:var(--step-diameter);border-radius:50%;background:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-alt-fg1, #495057);font-weight:400;font-size:14px;transition:all .2s ease-in-out;position:relative;transform:scale(.65)}.tn-stepper__step-number{font-weight:400}.tn-stepper__step-edit{--tn-icon-size: 18px}.tn-stepper__step-label{margin-top:8px}.tn-stepper__step-title ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-stepper__step-title{display:block;font-weight:400;font-size:14px;color:var(--tn-fg1, #000000);line-height:1.2}.tn-stepper__step-subtitle{display:block;font-size:12px;color:var(--tn-fg2, #6c757d);margin-top:2px}.tn-stepper__step-error-message{display:block;font-size:12px;color:var(--tn-red, #dc3545);margin-top:2px}.tn-stepper__step-header--active .tn-stepper__step-indicator{background:var(--tn-primary, #007bff);color:var(--tn-primary-txt, #ffffff);transform:scale(1)}.tn-stepper__step-header--active .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-indicator.tn-stepper__step-indicator--glyph{background:transparent;transform:scale(1)}.tn-stepper__step-indicator.tn-stepper__step-indicator--glyph tn-icon{--tn-icon-size: var(--step-diameter);line-height:1}.tn-stepper__step-header--active .tn-stepper__step-indicator.tn-stepper__step-indicator--glyph{background:transparent}.tn-stepper__step-header--error .tn-stepper__step-error{--tn-icon-color: var(--tn-red, #dc3545)}.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg1, #000000)}.tn-stepper__step-header--active.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--optional .tn-stepper__step-indicator{border:2px dashed var(--tn-lines, #e5e7eb);background:transparent}.tn-stepper__content{min-height:200px}.tn-stepper__step-content{padding:16px;background:var(--tn-bg1, #ffffff);border-radius:8px;border:1px solid var(--tn-lines, #e5e7eb)}.tn-stepper__step-header:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-stepper__step-header:focus:not(:focus-visible){outline:none}.tn-stepper__step-header[aria-disabled=true]{cursor:not-allowed}@media(max-width:780px){.tn-stepper--horizontal .tn-stepper__step-label{display:none}.tn-stepper--horizontal .tn-stepper__step-indicator{width:var(--step-diameter-sm);height:var(--step-diameter-sm);font-size:12px}.tn-stepper--horizontal .tn-stepper__header{padding:0 8px}.tn-stepper--horizontal .tn-stepper__connector{top:calc(var(--step-diameter-sm) / 2);margin:0 8px}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: TnTestIdDirective, selector: "[tnTestId]", inputs: ["tnTestId", "tnTestIdType"] }, { kind: "component", type: TnIconComponent, selector: "tn-icon", inputs: ["name", "size", "color", "tooltip", "ariaLabel", "library", "testId", "fullSize", "customSize"] }, { kind: "pipe", type: LabelMarkupPipe, name: "tnLabelMarkup" }], animations: [
15839
15871
  trigger('stepTransition', [
15840
15872
  transition(':enter', [
15841
15873
  style({ opacity: 0, transform: 'translateX(50px)' }),
@@ -15846,7 +15878,7 @@ class TnStepperComponent {
15846
15878
  }
15847
15879
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperComponent, decorators: [{
15848
15880
  type: Component,
15849
- args: [{ selector: 'tn-stepper', standalone: true, imports: [CommonModule, TnTestIdDirective, LabelMarkupPipe], animations: [
15881
+ args: [{ selector: 'tn-stepper', standalone: true, imports: [CommonModule, TnTestIdDirective, LabelMarkupPipe, TnIconComponent], animations: [
15850
15882
  trigger('stepTransition', [
15851
15883
  transition(':enter', [
15852
15884
  style({ opacity: 0, transform: 'translateX(50px)' }),
@@ -15854,10 +15886,139 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
15854
15886
  ])
15855
15887
  ])
15856
15888
  ], host: {
15857
- '(window:resize)': 'onWindowResize($event)'
15858
- }, template: "<div class=\"tn-stepper\"\n tnTestIdType=\"stepper\"\n [class.tn-stepper--horizontal]=\"orientation() === 'horizontal' || (orientation() === 'auto' && isWideScreen())\"\n [class.tn-stepper--vertical]=\"orientation() === 'vertical' || (orientation() === 'auto' && !isWideScreen())\"\n [tnTestId]=\"testId()\">\n\n <!-- Step Headers -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <div class=\"tn-stepper__step-header\"\n tabindex=\"0\"\n role=\"button\"\n [class.tn-stepper__step-header--active]=\"selectedIndex() === i\"\n [class.tn-stepper__step-header--completed]=\"step.completed()\"\n [class.tn-stepper__step-header--error]=\"step.hasError()\"\n [class.tn-stepper__step-header--optional]=\"step.optional()\"\n (click)=\"selectStep(i)\"\n (keydown.enter)=\"selectStep(i)\"\n (keydown.space)=\"selectStep(i)\">\n\n <!-- Step Number/Icon -->\n <div class=\"tn-stepper__step-indicator\">\n @if (step.completed() && !step.hasError()) {\n <span class=\"tn-stepper__step-check\">\u2713</span>\n }\n @if (step.hasError()) {\n <span class=\"tn-stepper__step-error\">!</span>\n }\n @if (!step.completed() && !step.hasError()) {\n @if (step.icon()) {\n <span class=\"tn-stepper__step-icon\">{{ step.icon() }}</span>\n } @else {\n <span class=\"tn-stepper__step-number\">{{ i + 1 }}</span>\n }\n }\n </div>\n\n <!-- Step Label -->\n <div class=\"tn-stepper__step-label\">\n <div class=\"tn-stepper__step-title\" [innerHTML]=\"step.label() | tnLabelMarkup\"></div>\n @if (step.optional()) {\n <span class=\"tn-stepper__step-subtitle\">Optional</span>\n }\n </div>\n </div>\n\n <!-- Connector Line (except for last step) -->\n @if (i < steps().length - 1) {\n <div class=\"tn-stepper__connector\"></div>\n }\n }\n </div>\n\n <!-- Step Content -->\n <div class=\"tn-stepper__content\">\n @for (step of steps(); track $index; let i = $index) {\n @if (selectedIndex() === i) {\n <div class=\"tn-stepper__step-content\"\n [@stepTransition]=\"selectedIndex()\">\n <ng-container *ngTemplateOutlet=\"step.content()\" />\n </div>\n }\n }\n </div>\n</div>", styles: [".tn-stepper{display:flex;font-family:inherit;--step-diameter: 48px;--step-diameter-sm: 32px;--step-padding: 12px}.tn-stepper--horizontal{flex-direction:column}.tn-stepper--horizontal .tn-stepper__header{display:flex;justify-content:center;margin-bottom:32px;padding:0 16px}.tn-stepper--horizontal .tn-stepper__step-header{display:flex;flex-direction:column;align-items:center;text-align:center;cursor:pointer;transition:all .2s ease-in-out}.tn-stepper--horizontal .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--horizontal .tn-stepper__connector{flex:1;height:2px;background:var(--tn-lines, #e5e7eb);margin:0 16px;position:relative;top:calc(var(--step-diameter) / 2)}.tn-stepper--vertical{flex-direction:row}.tn-stepper--vertical .tn-stepper__header{display:flex;flex-direction:column;width:280px;padding:16px;border-right:1px solid var(--tn-lines, #e5e7eb)}.tn-stepper--vertical .tn-stepper__step-header{display:flex;flex-direction:row;align-items:center;text-align:left;cursor:pointer;transition:all .2s ease-in-out;padding:var(--step-padding);border-radius:8px;margin-bottom:8px}.tn-stepper--vertical .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin-left:12px;margin-top:0}.tn-stepper--vertical .tn-stepper__connector{width:2px;height:24px;background:var(--tn-lines, #e5e7eb);position:relative;left:calc(var(--step-diameter) / 2 + var(--step-padding));margin-bottom:8px}.tn-stepper--vertical .tn-stepper__content{flex:1;padding:16px}.tn-stepper__step-indicator{display:flex;align-items:center;justify-content:center;width:var(--step-diameter);height:var(--step-diameter);border-radius:50%;background:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-alt-fg1, #495057);font-weight:400;font-size:14px;transition:all .2s ease-in-out;position:relative;transform:scale(.65)}.tn-stepper__step-number{font-weight:400}.tn-stepper__step-label{margin-top:8px}.tn-stepper__step-title ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-stepper__step-title{display:block;font-weight:400;font-size:14px;color:var(--tn-fg1, #000000);line-height:1.2}.tn-stepper__step-subtitle{display:block;font-size:12px;color:var(--tn-fg2, #6c757d);margin-top:2px}.tn-stepper__step-header--active .tn-stepper__step-indicator{background:var(--tn-primary, #007bff);color:var(--tn-primary-txt, #ffffff);transform:scale(1)}.tn-stepper__step-header--active .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--completed .tn-stepper__step-indicator{background:var(--tn-green, #28a745);color:#fff}.tn-stepper__step-header--completed .tn-stepper__step-check{font-size:1rem;font-weight:700}.tn-stepper__step-header--error .tn-stepper__step-indicator{background:var(--tn-red, #dc3545);color:#fff}.tn-stepper__step-header--error .tn-stepper__step-error{font-size:18px;font-weight:700}.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg1, #000000)}.tn-stepper__step-header--active.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--optional .tn-stepper__step-indicator{border:2px dashed var(--tn-lines, #e5e7eb);background:transparent}.tn-stepper--horizontal .tn-stepper__step-header--completed+.tn-stepper__connector{background:var(--tn-green, #28a745)}.tn-stepper--horizontal .tn-stepper__step-header--completed+.tn-stepper__connector:after{content:\"\";position:absolute;top:0;left:0;right:0;height:100%;background:var(--tn-green, #28a745);animation:progressFill .3s ease-in-out}.tn-stepper--vertical .tn-stepper__step-header--completed+.tn-stepper__connector{background:var(--tn-green, #28a745)}.tn-stepper__content{min-height:200px}.tn-stepper__step-content{padding:16px;background:var(--tn-bg1, #ffffff);border-radius:8px;border:1px solid var(--tn-lines, #e5e7eb)}@keyframes progressFill{0%{width:0}to{width:100%}}.tn-stepper__step-header:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-stepper__step-header:focus:not(:focus-visible){outline:none}@media(max-width:780px){.tn-stepper--vertical .tn-stepper__header{width:180px;border-right:none;border-bottom:1px solid var(--tn-lines, #e5e7eb);padding:16px 0}.tn-stepper--vertical .tn-stepper__step-header{flex-direction:column;align-items:center;text-align:center;min-width:80px;padding:8px 4px}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin-left:0;margin-top:8px}.tn-stepper--vertical .tn-stepper__connector{display:none}}@media(max-width:780px){.tn-stepper .tn-stepper__step-label{display:none}.tn-stepper .tn-stepper__step-indicator{width:var(--step-diameter-sm);height:var(--step-diameter-sm);font-size:12px}.tn-stepper--horizontal .tn-stepper__header{padding:0 8px}.tn-stepper--horizontal .tn-stepper__connector{top:calc(var(--step-diameter-sm) / 2);margin:0 8px}.tn-stepper--vertical .tn-stepper__header{width:60px}.tn-stepper--vertical .tn-stepper__step-header{padding:4px;margin-bottom:4px}.tn-stepper--vertical .tn-stepper__connector{left:calc(var(--step-diameter-sm) / 2 + 4px);height:16px;margin-bottom:4px}}\n"] }]
15889
+ '(window:resize)': 'onWindowResize()'
15890
+ }, template: "<div class=\"tn-stepper\"\n tnTestIdType=\"stepper\"\n [class.tn-stepper--horizontal]=\"!isVertical()\"\n [class.tn-stepper--vertical]=\"isVertical()\"\n [tnTestId]=\"testId()\">\n\n <!-- Shared step header (indicator + label) -->\n <ng-template #stepHeader let-step=\"step\" let-i=\"i\">\n <div class=\"tn-stepper__step-header\"\n role=\"button\"\n [attr.tabindex]=\"stepGated()[i] ? -1 : 0\"\n [attr.aria-current]=\"selectedIndex() === i ? 'step' : null\"\n [attr.aria-disabled]=\"stepGated()[i] ? 'true' : null\"\n [class.tn-stepper__step-header--active]=\"selectedIndex() === i\"\n [class.tn-stepper__step-header--completed]=\"step.completed()\"\n [class.tn-stepper__step-header--error]=\"step.hasError()\"\n [class.tn-stepper__step-header--optional]=\"step.optional()\"\n (click)=\"selectStep(i)\"\n (keydown.enter)=\"selectStep(i)\"\n (keydown.space)=\"$event.preventDefault(); selectStep(i)\">\n\n <!-- Step Number/Icon -->\n <div class=\"tn-stepper__step-indicator\"\n [class.tn-stepper__step-indicator--glyph]=\"step.hasError()\">\n @if (step.hasError()) {\n <tn-icon class=\"tn-stepper__step-error\" name=\"alert\" library=\"mdi\" [attr.aria-hidden]=\"true\" />\n } @else if (stepEditable()[i]) {\n <tn-icon class=\"tn-stepper__step-edit\" name=\"pencil\" library=\"mdi\" [attr.aria-hidden]=\"true\" />\n } @else if (step.icon()) {\n <span class=\"tn-stepper__step-icon\">{{ step.icon() }}</span>\n } @else {\n <span class=\"tn-stepper__step-number\">{{ i + 1 }}</span>\n }\n </div>\n\n <!-- Step Label -->\n <div class=\"tn-stepper__step-label\">\n <div class=\"tn-stepper__step-title\" [innerHTML]=\"step.label() | tnLabelMarkup\"></div>\n @if (step.hasError() && step.errorMessage()) {\n <span class=\"tn-stepper__step-error-message\">{{ step.errorMessage() }}</span>\n } @else if (step.optional()) {\n <span class=\"tn-stepper__step-subtitle\">Optional</span>\n }\n </div>\n </div>\n </ng-template>\n\n @if (isVertical()) {\n <!-- Vertical: content renders inline beneath the active step's header -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <div class=\"tn-stepper__step\" [class.tn-stepper__step--last]=\"i === steps().length - 1\">\n <ng-container *ngTemplateOutlet=\"stepHeader; context: { step, i }\" />\n\n <div class=\"tn-stepper__step-body\">\n @if (selectedIndex() === i) {\n <div class=\"tn-stepper__step-content\" [@stepTransition]=\"selectedIndex()\">\n <ng-container *ngTemplateOutlet=\"step.content()\" />\n </div>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <!-- Horizontal: headers in a row, active content below -->\n <div class=\"tn-stepper__header\">\n @for (step of steps(); track $index; let i = $index) {\n <ng-container *ngTemplateOutlet=\"stepHeader; context: { step, i }\" />\n\n @if (i < steps().length - 1) {\n <div class=\"tn-stepper__connector\"></div>\n }\n }\n </div>\n\n <div class=\"tn-stepper__content\">\n @for (step of steps(); track $index; let i = $index) {\n @if (selectedIndex() === i) {\n <div class=\"tn-stepper__step-content\"\n [@stepTransition]=\"selectedIndex()\">\n <ng-container *ngTemplateOutlet=\"step.content()\" />\n </div>\n }\n }\n </div>\n }\n</div>\n", styles: [".tn-stepper{display:flex;font-family:inherit;--step-diameter: 48px;--step-diameter-sm: 32px;--step-padding: 12px;--v-indicator: 32px;--v-gap: 12px}.tn-stepper--horizontal{flex-direction:column}.tn-stepper--horizontal .tn-stepper__header{display:flex;justify-content:center;margin-bottom:32px;padding:0 16px}.tn-stepper--horizontal .tn-stepper__step-header{display:flex;flex-direction:column;align-items:center;text-align:center;cursor:pointer;transition:all .2s ease-in-out}.tn-stepper--horizontal .tn-stepper__step-header:not(.tn-stepper__step-header--active):hover .tn-stepper__step-indicator{transform:scale(.95)}.tn-stepper--horizontal .tn-stepper__connector{flex:1;height:2px;background:var(--tn-lines, #e5e7eb);margin:0 16px;position:relative;top:calc(var(--step-diameter) / 2)}.tn-stepper--vertical{flex-direction:column}.tn-stepper--vertical .tn-stepper__header,.tn-stepper--vertical .tn-stepper__step{display:flex;flex-direction:column}.tn-stepper--vertical .tn-stepper__step-header{display:flex;flex-direction:row;align-items:center;gap:var(--v-gap);text-align:left;cursor:pointer;padding:8px 0}.tn-stepper--vertical .tn-stepper__step-header .tn-stepper__step-label{margin:0}.tn-stepper--vertical .tn-stepper__step-indicator{width:var(--v-indicator);height:var(--v-indicator);min-width:var(--v-indicator);font-size:13px;transform:none}.tn-stepper--vertical .tn-stepper__step-indicator--glyph tn-icon{--tn-icon-size: var(--v-indicator)}.tn-stepper--vertical .tn-stepper__step-header--active .tn-stepper__step-indicator{transform:none}.tn-stepper--vertical .tn-stepper__step-body{margin-left:calc(var(--v-indicator) / 2 - 1px);border-left:2px solid var(--tn-lines, #e5e7eb);padding-left:calc(var(--v-indicator) / 2 + var(--v-gap));padding-bottom:8px;min-height:12px}.tn-stepper--vertical .tn-stepper__step--last .tn-stepper__step-body{border-left-color:transparent;min-height:0}.tn-stepper--vertical .tn-stepper__step-content{padding:4px 0 8px;background:transparent;border:none;border-radius:0}.tn-stepper__step-indicator{display:flex;align-items:center;justify-content:center;width:var(--step-diameter);height:var(--step-diameter);border-radius:50%;background:var(--tn-alt-bg1, #f8f9fa);color:var(--tn-alt-fg1, #495057);font-weight:400;font-size:14px;transition:all .2s ease-in-out;position:relative;transform:scale(.65)}.tn-stepper__step-number{font-weight:400}.tn-stepper__step-edit{--tn-icon-size: 18px}.tn-stepper__step-label{margin-top:8px}.tn-stepper__step-title ::ng-deep code{font-family:var(--tn-font-family-monospace, monospace);font-size:.875em;background:var(--tn-bg2, #f5f5f5);border:1px solid var(--tn-lines, #ccc);border-radius:4px;padding:.125em .45em}.tn-stepper__step-title{display:block;font-weight:400;font-size:14px;color:var(--tn-fg1, #000000);line-height:1.2}.tn-stepper__step-subtitle{display:block;font-size:12px;color:var(--tn-fg2, #6c757d);margin-top:2px}.tn-stepper__step-error-message{display:block;font-size:12px;color:var(--tn-red, #dc3545);margin-top:2px}.tn-stepper__step-header--active .tn-stepper__step-indicator{background:var(--tn-primary, #007bff);color:var(--tn-primary-txt, #ffffff);transform:scale(1)}.tn-stepper__step-header--active .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-indicator.tn-stepper__step-indicator--glyph{background:transparent;transform:scale(1)}.tn-stepper__step-indicator.tn-stepper__step-indicator--glyph tn-icon{--tn-icon-size: var(--step-diameter);line-height:1}.tn-stepper__step-header--active .tn-stepper__step-indicator.tn-stepper__step-indicator--glyph{background:transparent}.tn-stepper__step-header--error .tn-stepper__step-error{--tn-icon-color: var(--tn-red, #dc3545)}.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg1, #000000)}.tn-stepper__step-header--active.tn-stepper__step-header--error .tn-stepper__step-title{color:var(--tn-fg2, #6c757d);font-weight:600}.tn-stepper__step-header--optional .tn-stepper__step-indicator{border:2px dashed var(--tn-lines, #e5e7eb);background:transparent}.tn-stepper__content{min-height:200px}.tn-stepper__step-content{padding:16px;background:var(--tn-bg1, #ffffff);border-radius:8px;border:1px solid var(--tn-lines, #e5e7eb)}.tn-stepper__step-header:focus{outline:2px solid var(--tn-primary, #007bff);outline-offset:2px}.tn-stepper__step-header:focus:not(:focus-visible){outline:none}.tn-stepper__step-header[aria-disabled=true]{cursor:not-allowed}@media(max-width:780px){.tn-stepper--horizontal .tn-stepper__step-label{display:none}.tn-stepper--horizontal .tn-stepper__step-indicator{width:var(--step-diameter-sm);height:var(--step-diameter-sm);font-size:12px}.tn-stepper--horizontal .tn-stepper__header{padding:0 8px}.tn-stepper--horizontal .tn-stepper__connector{top:calc(var(--step-diameter-sm) / 2);margin:0 8px}}\n"] }]
15859
15891
  }], ctorParameters: () => [], propDecorators: { orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], linear: [{ type: i0.Input, args: [{ isSignal: true, alias: "linear", required: false }] }], selectedIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIndex", required: false }] }, { type: i0.Output, args: ["selectedIndexChange"] }], testId: [{ type: i0.Input, args: [{ isSignal: true, alias: "testId", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], completed: [{ type: i0.Output, args: ["completed"] }], steps: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => TnStepComponent), { ...{ descendants: true }, isSignal: true }] }] } });
15860
15892
 
15893
+ /**
15894
+ * Advances the ancestor `<tn-stepper>` to the next step when the host is clicked.
15895
+ *
15896
+ * Mirrors Angular Material's `matStepperNext`. Place it on a button (native
15897
+ * `<button>` or `<tn-button>`) rendered inside a `<tn-step>` — including step
15898
+ * content that lives in a projected child component. The directive resolves the
15899
+ * stepper through the element injector, so a disabled host simply emits no click
15900
+ * and navigation is naturally gated.
15901
+ *
15902
+ * @example
15903
+ * ```html
15904
+ * <tn-button [tnStepperNext] [disabled]="form.invalid" [label]="'Next' | translate" />
15905
+ * ```
15906
+ */
15907
+ class TnStepperNextDirective {
15908
+ stepper = inject(TnStepperComponent);
15909
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperNextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
15910
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: TnStepperNextDirective, isStandalone: true, selector: "[tnStepperNext]", host: { listeners: { "click": "stepper.next()" } }, ngImport: i0 });
15911
+ }
15912
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperNextDirective, decorators: [{
15913
+ type: Directive,
15914
+ args: [{
15915
+ selector: '[tnStepperNext]',
15916
+ standalone: true,
15917
+ host: {
15918
+ '(click)': 'stepper.next()',
15919
+ },
15920
+ }]
15921
+ }] });
15922
+
15923
+ /**
15924
+ * Moves the ancestor `<tn-stepper>` to the previous step when the host is clicked.
15925
+ *
15926
+ * Mirrors Angular Material's `matStepperPrevious`. Place it on a button (native
15927
+ * `<button>` or `<tn-button>`) rendered inside a `<tn-step>` — including step
15928
+ * content that lives in a projected child component. The directive resolves the
15929
+ * stepper through the element injector.
15930
+ *
15931
+ * @example
15932
+ * ```html
15933
+ * <tn-button [tnStepperPrevious] [label]="'Back' | translate" />
15934
+ * ```
15935
+ */
15936
+ class TnStepperPreviousDirective {
15937
+ stepper = inject(TnStepperComponent);
15938
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperPreviousDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
15939
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.1.0", type: TnStepperPreviousDirective, isStandalone: true, selector: "[tnStepperPrevious]", host: { listeners: { "click": "stepper.previous()" } }, ngImport: i0 });
15940
+ }
15941
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperPreviousDirective, decorators: [{
15942
+ type: Directive,
15943
+ args: [{
15944
+ selector: '[tnStepperPrevious]',
15945
+ standalone: true,
15946
+ host: {
15947
+ '(click)': 'stepper.previous()',
15948
+ },
15949
+ }]
15950
+ }] });
15951
+
15952
+ /**
15953
+ * Harness for interacting with `tn-stepper` in tests.
15954
+ *
15955
+ * @example
15956
+ * ```typescript
15957
+ * const stepper = await loader.getHarness(TnStepperHarness);
15958
+ * expect(await stepper.getStepLabels()).toEqual(['Provider', 'What and When']);
15959
+ * expect(await stepper.getSelectedIndex()).toBe(0);
15960
+ * await stepper.selectStep(1);
15961
+ * ```
15962
+ */
15963
+ class TnStepperHarness extends ComponentHarness {
15964
+ /** The selector for the host element of a `TnStepperComponent` instance. */
15965
+ static hostSelector = 'tn-stepper';
15966
+ /**
15967
+ * Gets a `HarnessPredicate` used to search for a stepper with specific attributes.
15968
+ *
15969
+ * @param options Options for filtering which stepper instances are considered a match.
15970
+ */
15971
+ static with(options = {}) {
15972
+ return new HarnessPredicate(TnStepperHarness, options)
15973
+ .addOption('orientation', options.orientation, async (harness, orientation) => {
15974
+ return (await harness.getOrientation()) === orientation;
15975
+ });
15976
+ }
15977
+ headers = this.locatorForAll('.tn-stepper__step-header');
15978
+ /** Gets the number of steps. */
15979
+ async getStepCount() {
15980
+ return (await this.headers()).length;
15981
+ }
15982
+ /** Gets all step labels as strings, in order. */
15983
+ async getStepLabels() {
15984
+ const titles = await this.locatorForAll('.tn-stepper__step-title')();
15985
+ return Promise.all(titles.map(title => title.text()));
15986
+ }
15987
+ /** Gets the zero-based index of the currently selected step, or -1 if none. */
15988
+ async getSelectedIndex() {
15989
+ const headers = await this.headers();
15990
+ for (let i = 0; i < headers.length; i++) {
15991
+ if (await headers[i].hasClass('tn-stepper__step-header--active')) {
15992
+ return i;
15993
+ }
15994
+ }
15995
+ return -1;
15996
+ }
15997
+ /** Whether the step at `index` is marked completed. */
15998
+ async isStepCompleted(index) {
15999
+ const header = (await this.headers())[index];
16000
+ return header ? header.hasClass('tn-stepper__step-header--completed') : false;
16001
+ }
16002
+ /** Whether the step at `index` is marked as having an error. */
16003
+ async isStepError(index) {
16004
+ const header = (await this.headers())[index];
16005
+ return header ? header.hasClass('tn-stepper__step-header--error') : false;
16006
+ }
16007
+ /** Selects the step at `index` by clicking its header. Respects linear gating. */
16008
+ async selectStep(index) {
16009
+ const header = (await this.headers())[index];
16010
+ if (!header) {
16011
+ throw new Error(`No step at index ${index}`);
16012
+ }
16013
+ await header.click();
16014
+ }
16015
+ /** Gets the orientation of the stepper. */
16016
+ async getOrientation() {
16017
+ const root = await this.locatorFor('.tn-stepper')();
16018
+ return (await root.hasClass('tn-stepper--vertical')) ? 'vertical' : 'horizontal';
16019
+ }
16020
+ }
16021
+
15861
16022
  /**
15862
16023
  * Auto-generated from SVG files - DO NOT EDIT MANUALLY
15863
16024
  *
@@ -17674,5 +17835,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
17674
17835
  * Generated bundle index. Do not edit.
17675
17836
  */
17676
17837
 
17677
- export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, InputType, LIGHT_THEME, LabelMarkupPipe, LabelTextPipe, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, StripMntPrefixPipe, THEME_MAP, THEME_STORAGE_KEY, TN_FORM_FIELD_ERRORS, TN_TABLE_PAGER_DEFAULT_LABELS, TN_TABLE_PAGER_LABELS, TN_TEST_ATTR, TN_THEME_DEFINITIONS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarComponent, TnCalendarHeaderComponent, TnCardComponent, TnCardFooterActionsDirective, TnCardHeaderActionsDirective, TnCardHeaderDirective, TnCellDefDirective, TnCheckboxComponent, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnChipHarness, TnChipInputComponent, TnChipInputHarness, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDetailRowDefDirective, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFileInputComponent, TnFileInputHarness, TnFilePickerComponent, TnFilePickerPopupComponent, TnFormFieldComponent, TnFormFieldHarness, TnFormSectionComponent, TnFormSectionHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuItemComponent, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioHarness, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTableHarness, TnTablePagerComponent, TnTablePagerHarness, TnTabsComponent, TnTabsHarness, TnTestIdDirective, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeNodeComponent, TnTreeNodeOutletDirective, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, composeTestId, controlTestId, createLucideLibrary, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, formatSize, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, parseLabelMarkup, parseSize, registerLucideIcons, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
17838
+ export { CommonShortcuts, DEFAULT_THEME, DiskIconComponent, DiskType, FileSizePipe, InputType, LIGHT_THEME, LabelMarkupPipe, LabelTextPipe, LinuxModifierKeys, LinuxShortcuts, ModifierKeys, QuickShortcuts, ShortcutBuilder, StripMntPrefixPipe, THEME_MAP, THEME_STORAGE_KEY, TN_FORM_FIELD_ERRORS, TN_TABLE_PAGER_DEFAULT_LABELS, TN_TABLE_PAGER_LABELS, TN_TEST_ATTR, TN_THEME_DEFINITIONS, TnAutocompleteComponent, TnAutocompleteHarness, TnBannerActionDirective, TnBannerComponent, TnBannerHarness, TnBrandedSpinnerComponent, TnButtonComponent, TnButtonHarness, TnButtonToggleComponent, TnButtonToggleGroupComponent, TnButtonToggleGroupHarness, TnButtonToggleHarness, TnCalendarComponent, TnCalendarHeaderComponent, TnCardComponent, TnCardFooterActionsDirective, TnCardHeaderActionsDirective, TnCardHeaderDirective, TnCellDefDirective, TnCheckboxComponent, TnCheckboxHarness, TnCheckboxLabelDirective, TnChipComponent, TnChipHarness, TnChipInputComponent, TnChipInputHarness, TnConfirmDialogComponent, TnDateInputComponent, TnDateInputHarness, TnDateRangeInputComponent, TnDateRangeInputHarness, TnDetailRowDefDirective, TnDialog, TnDialogHarness, TnDialogShellComponent, TnDialogTesting, TnDividerComponent, TnDividerDirective, TnDrawerComponent, TnDrawerContainerComponent, TnDrawerContainerHarness, TnDrawerContentComponent, TnDrawerHarness, TnEmptyComponent, TnEmptyHarness, TnExpansionPanelComponent, TnExpansionPanelHarness, TnFileInputComponent, TnFileInputHarness, TnFilePickerComponent, TnFilePickerPopupComponent, TnFormFieldComponent, TnFormFieldHarness, TnFormSectionComponent, TnFormSectionHarness, TnHeaderCellDefDirective, TnIconButtonComponent, TnIconButtonHarness, TnIconComponent, TnIconHarness, TnIconRegistryService, TnIconTesting, TnInputComponent, TnInputDirective, TnInputHarness, TnKeyboardShortcutComponent, TnKeyboardShortcutService, TnListAvatarDirective, TnListComponent, TnListIconDirective, TnListItemComponent, TnListItemLineDirective, TnListItemPrimaryDirective, TnListItemSecondaryDirective, TnListItemTitleDirective, TnListItemTrailingDirective, TnListOptionComponent, TnListSubheaderComponent, TnMenuActivateHoverDirective, TnMenuComponent, TnMenuHarness, TnMenuItemComponent, TnMenuTesting, TnMenuTriggerDirective, TnMonthViewComponent, TnMultiYearViewComponent, TnNestedTreeNodeComponent, TnParticleProgressBarComponent, TnProgressBarComponent, TnRadioComponent, TnRadioHarness, TnSelectComponent, TnSelectHarness, TnSelectionListComponent, TnSidePanelActionDirective, TnSidePanelComponent, TnSidePanelHarness, TnSidePanelHeaderActionDirective, TnSlideToggleComponent, TnSlideToggleHarness, TnSliderComponent, TnSliderThumbDirective, TnSliderWithLabelDirective, TnSpinnerComponent, TnSpriteLoaderService, TnStepComponent, TnStepperComponent, TnStepperHarness, TnStepperNextDirective, TnStepperPreviousDirective, TnTabComponent, TnTabHarness, TnTabPanelComponent, TnTabPanelHarness, TnTableColumnDirective, TnTableComponent, TnTableHarness, TnTablePagerComponent, TnTablePagerHarness, TnTabsComponent, TnTabsHarness, TnTestIdDirective, TnTheme, TnThemeService, TnTimeInputComponent, TnToastComponent, TnToastMock, TnToastPosition, TnToastRef, TnToastService, TnToastTesting, TnToastType, TnTooltipComponent, TnTooltipDirective, TnTreeComponent, TnTreeFlatDataSource, TnTreeFlattener, TnTreeNodeComponent, TnTreeNodeOutletDirective, TruncatePathPipe, WindowsModifierKeys, WindowsShortcuts, composeTestId, controlTestId, createLucideLibrary, createShortcut, defaultSpriteBasePath, defaultSpriteConfigPath, formatSize, kebabTestSegment, labelMarkupToHtml, labelMarkupToText, libIconMarker, parseLabelMarkup, parseSize, registerLucideIcons, scopeTestId, setupLucideIntegration, tnIconMarker, writeTestId };
17678
17839
  //# sourceMappingURL=truenas-ui-components.mjs.map