@truenas/ui-components 0.3.15 → 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.
|
@@ -8865,7 +8865,6 @@ class TnSelectComponent {
|
|
|
8865
8865
|
}
|
|
8866
8866
|
onChange = (_value) => { };
|
|
8867
8867
|
onTouched = () => { };
|
|
8868
|
-
elementRef = inject(ElementRef);
|
|
8869
8868
|
cdr = inject(ChangeDetectorRef);
|
|
8870
8869
|
overlay = inject(Overlay);
|
|
8871
8870
|
viewContainerRef = inject(ViewContainerRef);
|
|
@@ -8937,11 +8936,19 @@ class TnSelectComponent {
|
|
|
8937
8936
|
*
|
|
8938
8937
|
* Why an overlay (vs. an inline absolutely-positioned panel):
|
|
8939
8938
|
* - Escapes parent `overflow: hidden`/clipping in surrounding layouts.
|
|
8940
|
-
* - `outsidePointerEvents()` notifies on outside pointerdown WITHOUT
|
|
8941
|
-
* intercepting the click (no backdrop) — so the user's click reaches
|
|
8942
|
-
* the underlying target while the select closes silently.
|
|
8943
8939
|
* - Position is recomputed on scroll so the panel stays attached.
|
|
8944
|
-
*
|
|
8940
|
+
*
|
|
8941
|
+
* Dismissal uses a transparent, full-viewport backdrop (`backdropClick()`).
|
|
8942
|
+
* We previously ran backdrop-less with `outsidePointerEvents()`, but that
|
|
8943
|
+
* only closes when the click lands strictly OUTSIDE the overlay pane — and
|
|
8944
|
+
* the pane was sized to the (often full-width) trigger while the panel itself
|
|
8945
|
+
* is only as wide as its content. The empty pane area to the right of the
|
|
8946
|
+
* options stayed `pointer-events: auto`, so clicks there never counted as
|
|
8947
|
+
* "outside" and the dropdown wouldn't close. A transparent backdrop closes on
|
|
8948
|
+
* ANY click outside the panel regardless of pane geometry — the standard
|
|
8949
|
+
* pattern used by native `<select>` and Material's `mat-select`. We therefore
|
|
8950
|
+
* also drop the explicit `width`: the pane sizes to the panel content so the
|
|
8951
|
+
* clickable surface matches what the user sees.
|
|
8945
8952
|
*/
|
|
8946
8953
|
attachOverlay() {
|
|
8947
8954
|
const trigger = this.triggerEl().nativeElement;
|
|
@@ -8955,25 +8962,17 @@ class TnSelectComponent {
|
|
|
8955
8962
|
this.overlayRef = this.overlay.create({
|
|
8956
8963
|
positionStrategy,
|
|
8957
8964
|
scrollStrategy: this.overlay.scrollStrategies.reposition(),
|
|
8958
|
-
hasBackdrop:
|
|
8959
|
-
|
|
8965
|
+
hasBackdrop: true,
|
|
8966
|
+
backdropClass: 'cdk-overlay-transparent-backdrop',
|
|
8960
8967
|
});
|
|
8961
8968
|
const portal = new TemplatePortal(this.dropdownTemplate(), this.viewContainerRef);
|
|
8962
8969
|
this.overlayRef.attach(portal);
|
|
8963
|
-
//
|
|
8964
|
-
//
|
|
8965
|
-
//
|
|
8966
|
-
//
|
|
8967
|
-
//
|
|
8968
|
-
|
|
8969
|
-
// trigger's click handler and the dropdown immediately reopens.
|
|
8970
|
-
this.overlaySubs.push(this.overlayRef.outsidePointerEvents().subscribe((event) => {
|
|
8971
|
-
const target = event.target;
|
|
8972
|
-
if (target && this.elementRef.nativeElement.contains(target)) {
|
|
8973
|
-
return;
|
|
8974
|
-
}
|
|
8975
|
-
this.closeDropdown(false);
|
|
8976
|
-
}));
|
|
8970
|
+
// Dismiss on any click outside the panel. The transparent backdrop spans
|
|
8971
|
+
// the viewport and captures the click, so this fires no matter where the
|
|
8972
|
+
// user clicks (including the empty area beside a narrow panel). Clicking
|
|
8973
|
+
// the trigger while open also hits the backdrop — it closes here and the
|
|
8974
|
+
// trigger's own click never fires, so there's no reopen race.
|
|
8975
|
+
this.overlaySubs.push(this.overlayRef.backdropClick().subscribe(() => this.closeDropdown(false)));
|
|
8977
8976
|
// Escape as a fallback (the trigger keydown handler covers the common case,
|
|
8978
8977
|
// but if focus ever moves into the panel, this catches it too).
|
|
8979
8978
|
this.overlaySubs.push(this.overlayRef.keydownEvents().subscribe((event) => {
|
|
@@ -15738,10 +15737,12 @@ class TnStepComponent {
|
|
|
15738
15737
|
optional = input(false, ...(ngDevMode ? [{ debugName: "optional" }] : []));
|
|
15739
15738
|
completed = input(false, ...(ngDevMode ? [{ debugName: "completed" }] : []));
|
|
15740
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" }] : []));
|
|
15741
15742
|
data = input(null, ...(ngDevMode ? [{ debugName: "data" }] : []));
|
|
15742
15743
|
content = viewChild.required('content');
|
|
15743
15744
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
15744
|
-
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: `
|
|
15745
15746
|
<ng-template #content>
|
|
15746
15747
|
<ng-content />
|
|
15747
15748
|
</ng-template>
|
|
@@ -15758,7 +15759,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
15758
15759
|
`,
|
|
15759
15760
|
standalone: true
|
|
15760
15761
|
}]
|
|
15761
|
-
}], 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 }] }] } });
|
|
15762
15763
|
|
|
15763
15764
|
class TnStepperComponent {
|
|
15764
15765
|
orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
|
|
@@ -15772,8 +15773,15 @@ class TnStepperComponent {
|
|
|
15772
15773
|
selectionChange = output();
|
|
15773
15774
|
completed = output();
|
|
15774
15775
|
steps = contentChildren(TnStepComponent, { ...(ngDevMode ? { debugName: "steps" } : {}), descendants: true });
|
|
15775
|
-
|
|
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" }] : []));
|
|
15776
15780
|
constructor() {
|
|
15781
|
+
effect(() => {
|
|
15782
|
+
const index = this.selectedIndex();
|
|
15783
|
+
this.maxReachedIndex.update((max) => Math.max(max, index));
|
|
15784
|
+
});
|
|
15777
15785
|
// Effect to check if all steps are completed
|
|
15778
15786
|
effect(() => {
|
|
15779
15787
|
// Trigger on any step completion change
|
|
@@ -15784,8 +15792,8 @@ class TnStepperComponent {
|
|
|
15784
15792
|
}
|
|
15785
15793
|
});
|
|
15786
15794
|
}
|
|
15787
|
-
onWindowResize(
|
|
15788
|
-
this.
|
|
15795
|
+
onWindowResize() {
|
|
15796
|
+
this.isWideScreen.set(window.innerWidth > 768);
|
|
15789
15797
|
}
|
|
15790
15798
|
_getStepData() {
|
|
15791
15799
|
return this.steps().map(step => ({
|
|
@@ -15794,10 +15802,33 @@ class TnStepperComponent {
|
|
|
15794
15802
|
data: step.data()
|
|
15795
15803
|
}));
|
|
15796
15804
|
}
|
|
15797
|
-
|
|
15798
|
-
|
|
15799
|
-
|
|
15800
|
-
|
|
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" }] : []));
|
|
15801
15832
|
selectStep(index) {
|
|
15802
15833
|
if (!this.linear() || this.canSelectStep(index)) {
|
|
15803
15834
|
const previousIndex = this.selectedIndex();
|
|
@@ -15836,7 +15867,7 @@ class TnStepperComponent {
|
|
|
15836
15867
|
return index;
|
|
15837
15868
|
}
|
|
15838
15869
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
15839
|
-
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: [
|
|
15840
15871
|
trigger('stepTransition', [
|
|
15841
15872
|
transition(':enter', [
|
|
15842
15873
|
style({ opacity: 0, transform: 'translateX(50px)' }),
|
|
@@ -15847,7 +15878,7 @@ class TnStepperComponent {
|
|
|
15847
15878
|
}
|
|
15848
15879
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: TnStepperComponent, decorators: [{
|
|
15849
15880
|
type: Component,
|
|
15850
|
-
args: [{ selector: 'tn-stepper', standalone: true, imports: [CommonModule, TnTestIdDirective, LabelMarkupPipe], animations: [
|
|
15881
|
+
args: [{ selector: 'tn-stepper', standalone: true, imports: [CommonModule, TnTestIdDirective, LabelMarkupPipe, TnIconComponent], animations: [
|
|
15851
15882
|
trigger('stepTransition', [
|
|
15852
15883
|
transition(':enter', [
|
|
15853
15884
|
style({ opacity: 0, transform: 'translateX(50px)' }),
|
|
@@ -15855,10 +15886,139 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
15855
15886
|
])
|
|
15856
15887
|
])
|
|
15857
15888
|
], host: {
|
|
15858
|
-
'(window:resize)': 'onWindowResize(
|
|
15859
|
-
}, template: "<div class=\"tn-stepper\"\n tnTestIdType=\"stepper\"\n [class.tn-stepper--horizontal]=\"
|
|
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"] }]
|
|
15860
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 }] }] } });
|
|
15861
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
|
+
|
|
15862
16022
|
/**
|
|
15863
16023
|
* Auto-generated from SVG files - DO NOT EDIT MANUALLY
|
|
15864
16024
|
*
|
|
@@ -17675,5 +17835,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImpor
|
|
|
17675
17835
|
* Generated bundle index. Do not edit.
|
|
17676
17836
|
*/
|
|
17677
17837
|
|
|
17678
|
-
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 };
|
|
17679
17839
|
//# sourceMappingURL=truenas-ui-components.mjs.map
|