|
hideDot
|
Type : boolean
|
Default value : false
|
|
|
|
hideLabel
|
Type : boolean
|
Default value : false
|
|
|
|
horizontal
|
Type : boolean
|
Default value : false
|
|
|
|
isForbidden
|
Type : boolean
|
Default value : false
|
|
|
|
labelId
|
Type : string
|
|
Required : true
|
|
|
|
state
|
Default value : StepState.PENDING
|
|
|
HostBindings
|
attr.aria-label
|
Type : any
|
|
|
|
attr.aria-labelledby
|
Type : any
|
|
|
|
attr.aria-selected
|
Type : "true" | "false"
|
|
|
|
attr.role
|
Type : string
|
Default value : 'tab'
|
|
|
|
attr.tabindex
|
Type : "0" | "-1"
|
|
|
|
class.is-horizontal
|
Type : any
|
|
|
|
class.is-interactive
|
Type : boolean
|
|
|
|
class.is-unclickable
|
Type : any
|
|
|
|
_elementRef
|
Type : ElementRef<HTMLElement>
|
|
|
|
role
|
Type : string
|
Default value : 'tab'
|
Decorators :
@HostBinding('attr.role')
|
|
|
Accessors
|
isHorizontal
|
getisHorizontal()
|
|
|
|
isUnclickable
|
getisUnclickable()
|
|
|
|
ariaLabelledBy
|
getariaLabelledBy()
|
|
|
|
ariaSelected
|
getariaSelected()
|
|
|
|
isComplete
|
getisComplete()
|
|
|
|
isInteractive
|
getisInteractive()
|
|
|
import { NxIconModule } from '@allianz/ng-aquila/icon';
import { FocusMonitor } from '@angular/cdk/a11y';
import { CdkStepHeader } from '@angular/cdk/stepper';
import {
ChangeDetectionStrategy,
Component,
ElementRef,
HostBinding,
OnDestroy,
inject,
input
} from '@angular/core';
import { StepState } from './navigation-step-state';
@Component({
selector: 'frame-navigation-step',
templateUrl: 'navigation-step.component.html',
styleUrls: [`./navigation-step.component.scss`],
imports: [NxIconModule],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class NavigationStepComponent extends CdkStepHeader implements OnDestroy {
override _elementRef: ElementRef<HTMLElement>;
private _focusMonitor = inject(FocusMonitor);
@HostBinding('attr.tabindex')
get tabindex() {
return this.state() === StepState.CURRENT ? '0' : '-1';
}
@HostBinding('attr.role') role = 'tab';
readonly horizontal = input(false);
readonly label = input<string>();
readonly state = input(StepState.PENDING);
readonly hideDot = input(false);
readonly isForbidden = input(false);
readonly hideLabel = input(false);
readonly labelId = input.required<string>();
@HostBinding('class.is-horizontal')
get isHorizontal() {
return this.horizontal();
}
@HostBinding('class.no-dot')
get isNoDot() {
return this.hideDot();
}
@HostBinding('class.is-unclickable')
get isUnclickable() {
return this.isForbidden();
}
@HostBinding('attr.aria-labelledby')
get ariaLabelledBy() {
return this.label() && !this.hideLabel() ? this.labelId() : null;
}
// Fallback in case the label is hidden
@HostBinding('attr.aria-label')
get ariaLabel() {
if (this.hideLabel()) {
return this.isComplete ? 'Completed ' + this.label() : this.label() || null;
}
return null;
}
@HostBinding('attr.aria-selected')
get ariaSelected() {
return this.isCurrent ? 'true' : 'false';
}
constructor() {
super();
this._elementRef = inject<ElementRef<HTMLElement>>(ElementRef);
this._focusMonitor.monitor(this._elementRef);
}
ngOnDestroy() {
this._focusMonitor.stopMonitoring(this._elementRef);
}
@HostBinding('class.is-current')
get isCurrent() {
return this.state() === StepState.CURRENT;
}
@HostBinding('class.is-complete')
get isComplete() {
return this.state() === StepState.COMPLETE;
}
@HostBinding('class.is-interactive')
get isInteractive() {
return this.state() === StepState.COMPLETE;
}
@HostBinding('class.is-unknown')
get isUnknown() {
return this.state() === StepState.UNKNOWN;
}
@HostBinding('class.is-pending')
get isPending() {
return this.state() === StepState.PENDING;
}
}
<div class="dot">
<div class="inner-dot"></div>
<nx-icon class="checkmark" name="check"></nx-icon>
</div>
<div class="label-wrapper" [id]="labelId()">
@if (isComplete) {
<span class="sr-only" i18n="@@frame.navigation-step.completed">Completed: </span>
} @if (label() && !hideLabel()) {
<span class="label">{{ label() }}</span>
}
</div>
$dot-size: 8px;
$dot-border-size: 2px;
:host {
display: flex;
position: relative;
align-items: center;
font-size: var(--multi-stepper-step-font-size);
min-height: 20px;
}
:host(.is-horizontal) {
flex: 1;
flex-direction: column;
}
:host:focus {
outline: none;
}
:host(.cdk-keyboard-focused) {
.dot {
box-shadow: 0 0 0 2px var(--multi-stepper-dot-checkmark-color),
0 0 0 6px var(--multi-stepper-dot-touched-color);
}
}
.label {
margin-left: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
:host(.is-horizontal) .label {
margin-left: 0;
white-space: initial;
text-align: center;
}
:host(.is-interactive) .dot,
:host(.is-interactive) .label {
cursor: pointer;
}
.dot {
flex-shrink: 0;
border-radius: 50%;
width: 2 * $dot-size;
height: 2 * $dot-size;
border: $dot-border-size solid var(--multi-stepper-dot-touched-color);
position: relative;
font-size: 16px;
}
:host(.no-dot) .dot {
display: none;
}
:host(.is-horizontal) .dot {
margin-bottom: $dot-size;
}
.icon {
font-size: 16px;
}
.inner-dot {
width: $dot-size;
height: $dot-size;
border-radius: 50%;
background-color: var(--multi-stepper-dot-touched-color);
transform: translate($dot-border-size, $dot-border-size);
position: absolute;
display: none;
}
.checkmark {
position: absolute;
transform: translate(-$dot-border-size, -$dot-border-size);
display: none;
}
:host(.is-complete) {
.dot {
background-color: var(--multi-stepper-dot-touched-color);
color: var(--multi-stepper-dot-checkmark-color);
}
.checkmark {
display: block;
}
}
:host(.is-current) {
.dot {
color: var(--multi-stepper-dot-checkmark-color);
}
.inner-dot {
display: block;
}
cursor: pointer;
}
:host(.is-current:not(.is-horizontal)) {
.label {
font-weight: 700;
}
}
:host(.is-unknown) {
.dot {
border-color: var(--multi-stepper-dot-disabled-color);
}
cursor: not-allowed;
}
:host(.is-pending) {
color: var(--multi-stepper-step-disabled-color);
.dot {
border: $dot-border-size solid var(--multi-stepper-dot-disabled-color);
}
cursor: not-allowed;
}
:host(.is-unclickable) {
.dot,
.label {
cursor: not-allowed;
}
cursor: not-allowed;
}
:host(:not(.no-dot):not(.is-horizontal)) {
margin-bottom: 2 * $dot-size + 2 * $dot-border-size;
&:not(:last-child)::before {
content: '';
position: absolute;
top: 3 * $dot-size - $dot-border-size;
left: $dot-size - $dot-border-size;
border-left: calc($dot-size / 2) dotted var(--multi-stepper-line-color);
height: 2 * $dot-size;
}
&.is-complete::before {
border-left-style: solid;
border-left-color: var(--multi-stepper-dot-touched-color);
height: 3 * $dot-size;
margin: (-2 * $dot-border-size) 0;
}
}
:host(:not(.no-dot).is-horizontal) {
&:not(:last-child)::before {
content: '';
position: absolute;
top: $dot-size - $dot-border-size;
left: (3 * $dot-size);
border-top: calc($dot-size / 2) dotted var(--multi-stepper-line-color);
height: 0;
width: calc(100% - #{3 * $dot-size});
transform: translateX(50%);
}
&.is-complete::before {
border-top-style: solid;
border-top-color: var(--multi-stepper-dot-touched-color);
left: (2 * $dot-size);
width: calc(100% - #{2 * $dot-size});
}
}
:host-context(.is-a1).is-horizontal {
--a1-dot-size: var(--semantic-size-content-m, 24px);
--a1-dot-radius: calc(var(--a1-dot-size) / 2);
--a1-item-gap: var(--semantic-gap-all-linear-300, 12px);
align-items: flex-start;
.dot {
width: var(--a1-dot-size);
height: var(--a1-dot-size);
font-size: var(--a1-dot-size);
}
&.is-current .inner-dot {
display: none;
}
&.is-complete .dot {
background-color: var(--semantic-color-signal-attention-positive-resting);
border-color: var(--semantic-color-signal-attention-positive-resting);
}
&:last-child {
min-width: 0;
flex-grow: 0;
align-items: flex-end;
.label {
white-space: nowrap;
overflow: visible;
}
}
}
:host-context(.is-a1).is-horizontal:not(:last-child):not(:first-child) .label-wrapper {
position: relative;
left: var(--a1-dot-radius);
transform: translateX(-50%);
}
:host-context(.is-a1).is-horizontal:not(.no-dot) {
&:not(:last-child)::before {
content: '';
position: absolute;
top: calc(var(--a1-dot-radius) - #{$dot-border-size});
height: 2px;
border-radius: 4px;
background: var(--semantic-color-border-secondary-disabled);
border-top: none;
transform: none;
}
&.is-complete::before {
background: var(--semantic-color-signal-attention-positive-resting);
}
&:not(:last-child):not(:nth-last-child(2))::before {
left: calc(2 * var(--a1-dot-radius) + var(--a1-item-gap));
width: calc(100% - 2 * var(--a1-dot-radius) - 2 * var(--a1-item-gap));
}
&:nth-last-child(2)::before {
left: calc(2 * var(--a1-dot-radius) + var(--a1-item-gap));
width: calc(100% - 4 * var(--a1-dot-radius) - 2 * var(--a1-item-gap));
}
}
.sr-only {
display: block;
width: 1px;
height: 1px;
margin: -1px;
overflow: hidden;
}
Legend
Html element with directive