/
githubmirror
/
components
Обзор
Документация
Войти
/
githubmirror
/
components
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/material/button/button.scss
357 строк
14 KB
Jeremy Mowery
feat(material/button): Add support for showing a progress indicator inside the button (#32698)
27 фев 2026, 02:02
Не верифицирован
27 фев 2026, 02:02
b4a89d5
Код
Авторство
О чём код?
@use './button-base'; @use '../core/style/private' as style-private; @use '../core/style/vendor-prefixes'; @use '../core/tokens/token-utils'; @use '../core/focus-indicators/private' as focus-indicators-private; @use './m3-button'; @use '../progress-spinner/progress-spinner-theme'; $fallbacks: m3-button.get-tokens(); .mat-mdc-button-base { text-decoration: none; // Makes button icon not cut off/shrink making the icon visible to fix b/411228600 & .mat-icon { // stylelint-disable material/no-prefixes min-height: fit-content; flex-shrink: 0; } // Hide the hover ripple on devices that don't support hover. Note that we have the `span` // in the selector in order to increase the specificity over the actual hover styles. @media (hover: none) { &:hover > span.mat-mdc-button-persistent-ripple::before { opacity: 0; } } } .mdc-button { @include vendor-prefixes.user-select(none); position: relative; display: inline-flex; align-items: center; justify-content: center; box-sizing: border-box; min-width: 64px; border: none; outline: none; line-height: inherit; -webkit-appearance: none; overflow: visible; vertical-align: middle; background: transparent; padding: 0 8px; &::-moz-focus-inner { padding: 0; border: 0; } &:active { outline: none; } &:hover { cursor: pointer; } &:disabled { cursor: default; pointer-events: none; } &[hidden] { display: none; } .mdc-button__label { position: relative; } } .mat-mdc-button { padding: 0 #{token-utils.slot(button-text-horizontal-padding, $fallbacks, true)}; height: token-utils.slot(button-text-container-height, $fallbacks); font-family: token-utils.slot(button-text-label-text-font, $fallbacks); font-size: token-utils.slot(button-text-label-text-size, $fallbacks); letter-spacing: token-utils.slot(button-text-label-text-tracking, $fallbacks); text-transform: token-utils.slot(button-text-label-text-transform, $fallbacks); font-weight: token-utils.slot(button-text-label-text-weight, $fallbacks); &, .mdc-button__ripple { border-radius: token-utils.slot(button-text-container-shape, $fallbacks); } &:not(:disabled) { color: token-utils.slot(button-text-label-text-color, $fallbacks); } // We need to re-apply the disabled tokens since MDC uses // `:disabled` which doesn't apply to anchors. @include button-base.mat-private-button-disabled { color: token-utils.slot(button-text-disabled-label-text-color, $fallbacks); } @include button-base.mat-private-button-horizontal-layout( button-text-icon-spacing, button-text-icon-offset, button-text-with-icon-horizontal-padding, $fallbacks); @include button-base.mat-private-button-ripple( button-text-ripple-color, button-text-state-layer-color, button-text-disabled-state-layer-color, button-text-hover-state-layer-opacity, button-text-focus-state-layer-opacity, button-text-pressed-state-layer-opacity, $fallbacks); @include button-base.mat-private-button-touch-target(false, button-text-touch-target-size, button-text-touch-target-display, $fallbacks); } .mat-mdc-unelevated-button { transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1); height: token-utils.slot(button-filled-container-height, $fallbacks); font-family: token-utils.slot(button-filled-label-text-font, $fallbacks); font-size: token-utils.slot(button-filled-label-text-size, $fallbacks); letter-spacing: token-utils.slot(button-filled-label-text-tracking, $fallbacks); text-transform: token-utils.slot(button-filled-label-text-transform, $fallbacks); font-weight: token-utils.slot(button-filled-label-text-weight, $fallbacks); padding: 0 #{token-utils.slot(button-filled-horizontal-padding, $fallbacks, true)}; @include button-base.mat-private-button-horizontal-layout( button-filled-icon-spacing, button-filled-icon-offset, null, $fallbacks); @include button-base.mat-private-button-ripple( button-filled-ripple-color, button-filled-state-layer-color, button-filled-disabled-state-layer-color, button-filled-hover-state-layer-opacity, button-filled-focus-state-layer-opacity, button-filled-pressed-state-layer-opacity, $fallbacks); @include button-base.mat-private-button-touch-target(false, button-filled-touch-target-size, button-filled-touch-target-display, $fallbacks); &:not(:disabled) { color: token-utils.slot(button-filled-label-text-color, $fallbacks); background-color: token-utils.slot(button-filled-container-color, $fallbacks); } &, .mdc-button__ripple { border-radius: token-utils.slot(button-filled-container-shape, $fallbacks); } .mat-mdc-button-progress-indicator-container { @include progress-spinner-theme.overrides( (active-indicator-color: token-utils.slot( button-filled-progress-active-indicator-color, $fallbacks)) ); } // We need to re-apply the disabled tokens since MDC uses // `:disabled` which doesn't apply to anchors. @include button-base.mat-private-button-disabled { color: token-utils.slot(button-filled-disabled-label-text-color, $fallbacks); background-color: token-utils.slot(button-filled-disabled-container-color, $fallbacks); } } .mat-mdc-raised-button { transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1); box-shadow: token-utils.slot(button-protected-container-elevation-shadow, $fallbacks); height: token-utils.slot(button-protected-container-height, $fallbacks); font-family: token-utils.slot(button-protected-label-text-font, $fallbacks); font-size: token-utils.slot(button-protected-label-text-size, $fallbacks); letter-spacing: token-utils.slot(button-protected-label-text-tracking, $fallbacks); text-transform: token-utils.slot(button-protected-label-text-transform, $fallbacks); font-weight: token-utils.slot(button-protected-label-text-weight, $fallbacks); padding: 0 #{token-utils.slot(button-protected-horizontal-padding, $fallbacks, true)}; @include button-base.mat-private-button-horizontal-layout( button-protected-icon-spacing, button-protected-icon-offset, null, $fallbacks); @include button-base.mat-private-button-ripple( button-protected-ripple-color, button-protected-state-layer-color, button-protected-disabled-state-layer-color, button-protected-hover-state-layer-opacity, button-protected-focus-state-layer-opacity, button-protected-pressed-state-layer-opacity, $fallbacks); @include button-base.mat-private-button-touch-target(false, button-protected-touch-target-size, button-protected-touch-target-display, $fallbacks); &:not(:disabled) { color: token-utils.slot(button-protected-label-text-color, $fallbacks); background-color: token-utils.slot(button-protected-container-color, $fallbacks); } &, .mdc-button__ripple { border-radius: token-utils.slot(button-protected-container-shape, $fallbacks); } @media (hover: hover) { &:hover { box-shadow: token-utils.slot(button-protected-hover-container-elevation-shadow, $fallbacks); } } &:focus { box-shadow: token-utils.slot(button-protected-focus-container-elevation-shadow, $fallbacks); } &:active, &:focus:active { box-shadow: token-utils.slot(button-protected-pressed-container-elevation-shadow, $fallbacks); } // We need to re-apply the disabled tokens since MDC uses // `:disabled` which doesn't apply to anchors. @include button-base.mat-private-button-disabled { color: token-utils.slot(button-protected-disabled-label-text-color, $fallbacks); background-color: token-utils.slot(button-protected-disabled-container-color, $fallbacks); &.mat-mdc-button-disabled { box-shadow: token-utils.slot( button-protected-disabled-container-elevation-shadow, $fallbacks); } } } .mat-mdc-outlined-button { border-style: solid; transition: border 280ms cubic-bezier(0.4, 0, 0.2, 1); height: token-utils.slot(button-outlined-container-height, $fallbacks); font-family: token-utils.slot(button-outlined-label-text-font, $fallbacks); font-size: token-utils.slot(button-outlined-label-text-size, $fallbacks); letter-spacing: token-utils.slot(button-outlined-label-text-tracking, $fallbacks); text-transform: token-utils.slot(button-outlined-label-text-transform, $fallbacks); font-weight: token-utils.slot(button-outlined-label-text-weight, $fallbacks); border-radius: token-utils.slot(button-outlined-container-shape, $fallbacks); border-width: token-utils.slot(button-outlined-outline-width, $fallbacks); padding: 0 #{token-utils.slot(button-outlined-horizontal-padding, $fallbacks, true)}; @include button-base.mat-private-button-horizontal-layout( button-outlined-icon-spacing, button-outlined-icon-offset, null, $fallbacks); @include button-base.mat-private-button-ripple( button-outlined-ripple-color, button-outlined-state-layer-color, button-outlined-disabled-state-layer-color, button-outlined-hover-state-layer-opacity, button-outlined-focus-state-layer-opacity, button-outlined-pressed-state-layer-opacity, $fallbacks); @include button-base.mat-private-button-touch-target(false, button-outlined-touch-target-size, button-outlined-touch-target-display, $fallbacks); &:not(:disabled) { color: token-utils.slot(button-outlined-label-text-color, $fallbacks); border-color: token-utils.slot(button-outlined-outline-color, $fallbacks); } // We need to re-apply the disabled tokens since MDC uses // `:disabled` which doesn't apply to anchors. @include button-base.mat-private-button-disabled { color: token-utils.slot(button-outlined-disabled-label-text-color, $fallbacks); border-color: token-utils.slot(button-outlined-disabled-outline-color, $fallbacks); } } .mat-tonal-button { transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1); height: token-utils.slot(button-tonal-container-height, $fallbacks); font-family: token-utils.slot(button-tonal-label-text-font, $fallbacks); font-size: token-utils.slot(button-tonal-label-text-size, $fallbacks); letter-spacing: token-utils.slot(button-tonal-label-text-tracking, $fallbacks); text-transform: token-utils.slot(button-tonal-label-text-transform, $fallbacks); font-weight: token-utils.slot(button-tonal-label-text-weight, $fallbacks); padding: 0 #{token-utils.slot(button-tonal-horizontal-padding, $fallbacks, true)}; &:not(:disabled) { color: token-utils.slot(button-tonal-label-text-color, $fallbacks); background-color: token-utils.slot(button-tonal-container-color, $fallbacks); } &, .mdc-button__ripple { border-radius: token-utils.slot(button-tonal-container-shape, $fallbacks); } // We need to re-apply the disabled tokens since MDC uses // `:disabled` which doesn't apply to anchors. @include button-base.mat-private-button-disabled { color: token-utils.slot(button-tonal-disabled-label-text-color, $fallbacks); background-color: token-utils.slot(button-tonal-disabled-container-color, $fallbacks); } @include button-base.mat-private-button-horizontal-layout( button-tonal-icon-spacing, button-tonal-icon-offset, null, $fallbacks); @include button-base.mat-private-button-ripple( button-tonal-ripple-color, button-tonal-state-layer-color, button-tonal-disabled-state-layer-color, button-tonal-hover-state-layer-opacity, button-tonal-focus-state-layer-opacity, button-tonal-pressed-state-layer-opacity, $fallbacks); @include button-base.mat-private-button-touch-target(false, button-tonal-touch-target-size, button-tonal-touch-target-display, $fallbacks); } .mat-mdc-button, .mat-mdc-unelevated-button, .mat-mdc-raised-button, .mat-mdc-outlined-button, .mat-tonal-button { @include button-base.mat-private-button-interactive(); @include style-private.private-animation-noop(); // Similar to MDC's `_icon-structure`, apart from the margin which we // handle via custom tokens in `mat-private-button-horizontal-layout`. & > .mat-icon { $icon-size: 1.125rem; display: inline-block; position: relative; vertical-align: top; font-size: $icon-size; height: $icon-size; width: $icon-size; } } // Since the stroked button has has an actual border that reduces the available space for // child elements such as the ripple container or focus overlay, an inherited border radius // for the absolute-positioned child elements does not work properly. This is because the // child element cannot expand to the same boundaries as the parent element with a border. // In order to work around this issue by *not* hiding overflow, we adjust the child elements // to fully cover the actual button element. This means that the border-radius would be correct // then. See: https://github.com/angular/components/issues/13738 .mat-mdc-outlined-button .mat-mdc-button-ripple, .mat-mdc-outlined-button .mdc-button__ripple { $offset: -1px; top: $offset; left: $offset; bottom: $offset; right: $offset; } // For the button element, default inset/offset values are necessary to ensure that // the focus indicator is sufficiently contrastive and renders appropriately. .mat-mdc-unelevated-button, .mat-tonal-button, .mat-mdc-raised-button { .mat-focus-indicator::before { $default-border-width: focus-indicators-private.$default-border-width; $border-width: var(--mat-focus-indicator-border-width, #{$default-border-width}); $offset: calc(#{$border-width} + 2px); margin: calc(#{$offset} * -1); } } .mat-mdc-outlined-button .mat-focus-indicator::before { $default-border-width: focus-indicators-private.$default-border-width; $border-width: var(--mat-focus-indicator-border-width, #{$default-border-width}); $offset: calc(#{$border-width} + 3px); margin: calc(#{$offset} * -1); } .mat-mdc-button-progress-indicator-container { position: absolute; inset-inline-start: 0; inset-block-start: 0; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; box-sizing: border-box; } .mat-mdc-button-progress-indicator-shown { mat-icon, [matButtonIcon], .mdc-button__label { visibility: hidden; } }