@use 'sass:math'; @use '@angular/cdk'; @use '../core/tokens/m2/mat/stepper' as tokens-mat-stepper; @use '../core/tokens/token-utils'; @use './stepper-variables'; // Gets the `calc` expression for the vertical padding of the stepper header. @function _get-vertical-padding-calc() { $height: token-utils.get-token-variable(header-height); @return calc(calc(#{$height} - #{stepper-variables.$label-header-height}) / 2); } .mat-stepper-vertical, .mat-stepper-horizontal { display: block; @include token-utils.use-tokens( tokens-mat-stepper.$prefix, tokens-mat-stepper.get-token-slots()) { @include token-utils.create-token-slot(font-family, container-text-font); @include token-utils.create-token-slot(background, container-color); } } .mat-horizontal-stepper-header-container { white-space: nowrap; display: flex; align-items: center; .mat-stepper-label-position-bottom & { align-items: flex-start; } .mat-stepper-header-position-bottom & { order: 1; } } .mat-stepper-horizontal-line { border-top-width: stepper-variables.$line-width; border-top-style: solid; flex: auto; height: 0; margin: 0 stepper-variables.$line-gap - stepper-variables.$side-gap; min-width: stepper-variables.$line-gap + stepper-variables.$side-gap; @include token-utils.use-tokens( tokens-mat-stepper.$prefix, tokens-mat-stepper.get-token-slots()) { @include token-utils.create-token-slot(border-top-color, line-color); .mat-stepper-label-position-bottom & { $vertical-padding: _get-vertical-padding-calc(); margin: 0; min-width: 0; position: relative; // Ensures that the horizontal line for the step content is aligned centered vertically. top: calc(#{$vertical-padding} + #{math.div(stepper-variables.$label-header-height, 2)}); } } } %mat-header-horizontal-line-label-position-bottom { $half-side-gap: math.div(stepper-variables.$side-gap, 2); border-top-width: stepper-variables.$line-width; border-top-style: solid; content: ''; display: inline-block; height: 0; position: absolute; width: calc(50% - #{$half-side-gap + stepper-variables.$line-gap}); } .mat-horizontal-stepper-header { display: flex; height: stepper-variables.$header-height; overflow: hidden; align-items: center; padding: 0 stepper-variables.$side-gap; @include token-utils.use-tokens( tokens-mat-stepper.$prefix, tokens-mat-stepper.get-token-slots()) { @include token-utils.create-token-slot(height, header-height); } .mat-step-icon { margin-right: stepper-variables.$line-gap; flex: none; [dir='rtl'] & { margin-right: 0; margin-left: stepper-variables.$line-gap; } } @include token-utils.use-tokens( tokens-mat-stepper.$prefix, tokens-mat-stepper.get-token-slots()) { $vertical-padding: _get-vertical-padding-calc(); &::before, &::after { @include token-utils.create-token-slot(border-top-color, line-color); } .mat-stepper-label-position-bottom & { padding: #{$vertical-padding} stepper-variables.$side-gap; &::before, &::after { // Ensures that the horizontal lines for the step header are centered vertically. top: calc(#{$vertical-padding} + #{math.div(stepper-variables.$label-header-height, 2)}); } } } .mat-stepper-label-position-bottom & { box-sizing: border-box; flex-direction: column; // We use auto instead of fixed 104px (by spec) because when there is an optional step // the height is greater than that height: auto; &:not(:last-child)::after, [dir='rtl'] &:not(:first-child)::after { @extend %mat-header-horizontal-line-label-position-bottom; right: 0; } &:not(:first-child)::before, [dir='rtl'] &:not(:last-child)::before { @extend %mat-header-horizontal-line-label-position-bottom; left: 0; } [dir='rtl'] &:last-child::before, [dir='rtl'] &:first-child::after { display: none; } & .mat-step-icon { // Cleans margin both for ltr and rtl direction margin-right: 0; margin-left: 0; } & .mat-step-label { padding: stepper-variables.$label-position-bottom-top-gap 0 0 0; text-align: center; width: 100%; } } } .mat-vertical-stepper-header { display: flex; align-items: center; // We can't use `max-height` here, because it breaks the flexbox centering in IE. height: stepper-variables.$label-header-height; @include token-utils.use-tokens( tokens-mat-stepper.$prefix, tokens-mat-stepper.get-token-slots()) { padding: #{_get-vertical-padding-calc()} stepper-variables.$side-gap; } .mat-step-icon { margin-right: stepper-variables.$vertical-stepper-content-margin - stepper-variables.$side-gap; [dir='rtl'] & { margin-right: 0; margin-left: stepper-variables.$vertical-stepper-content-margin - stepper-variables.$side-gap; } } } .mat-horizontal-stepper-wrapper { display: flex; flex-direction: column; } .mat-horizontal-stepper-content { outline: 0; &.mat-horizontal-stepper-content-inactive { height: 0; overflow: hidden; } // Used to avoid an issue where when the stepper is nested inside a component that // changes the `visibility` as a part of an Angular animation, the stepper's content // stays hidden (see #25925). The value has to be `!important` to override the incorrect // `visibility` from the animations package. This can also be solved using `visibility: visible` // on `.mat-horizontal-stepper-content`, but it can allow tabbing into hidden content. &:not(.mat-horizontal-stepper-content-inactive) { visibility: inherit !important; } } .mat-horizontal-content-container { overflow: hidden; padding: 0 stepper-variables.$side-gap stepper-variables.$side-gap stepper-variables.$side-gap; @include cdk.high-contrast { outline: solid 1px; } .mat-stepper-header-position-bottom & { padding: stepper-variables.$side-gap stepper-variables.$side-gap 0 stepper-variables.$side-gap; } } .mat-vertical-content-container { margin-left: stepper-variables.$vertical-stepper-content-margin; border: 0; position: relative; @include cdk.high-contrast { outline: solid 1px; } [dir='rtl'] & { margin-left: 0; margin-right: stepper-variables.$vertical-stepper-content-margin; } } .mat-stepper-vertical-line::before { content: ''; position: absolute; left: 0; border-left-width: stepper-variables.$line-width; border-left-style: solid; @include token-utils.use-tokens( tokens-mat-stepper.$prefix, tokens-mat-stepper.get-token-slots()) { $vertical-padding: _get-vertical-padding-calc(); $vertical-offset: calc(#{stepper-variables.$line-gap} - #{$vertical-padding}); @include token-utils.create-token-slot(border-left-color, line-color); // Ensures that the vertical lines for the step content exceed into the step // headers with a given distance (`$mat-stepper-line-gap`) to the step icon. top: $vertical-offset; bottom: $vertical-offset; } [dir='rtl'] & { left: auto; right: 0; } } .mat-vertical-stepper-content { overflow: hidden; outline: 0; // Used to avoid an issue where when the stepper is nested inside a component that // changes the `visibility` as a part of an Angular animation, the stepper's content // stays hidden (see #25925). The value has to be `!important` to override the incorrect // `visibility` from the animations package. This can also be solved using `visibility: visible` // on `.mat-vertical-stepper-content`, but it can allow tabbing into hidden content. &:not(.mat-vertical-stepper-content-inactive) { visibility: inherit !important; } } .mat-vertical-content { padding: 0 stepper-variables.$side-gap stepper-variables.$side-gap stepper-variables.$side-gap; } .mat-step:last-child { .mat-vertical-content-container { border: none; } }