sass-references/angular-material/material/button/_button-base.scss

182 lines
6.0 KiB
SCSS
Raw Permalink Normal View History

2024-12-06 10:42:08 +08:00
@use '../core/tokens/token-utils';
@use '../core/style/layout-common';
// Adds styles necessary to provide stateful interactions with the button. This includes providing
// content for the state container's ::before and ::after so that they can be given a background
// color and opacity for states like hover, active, and focus. Additionally, adds styles to the
// ripple and state container so that they fill the button, match the border radius, and avoid
// pointer events.
@mixin mat-private-button-interactive() {
-webkit-tap-highlight-color: transparent;
// The ripple container should match the bounds of the entire button.
.mat-mdc-button-ripple,
.mat-mdc-button-persistent-ripple,
.mat-mdc-button-persistent-ripple::before {
@include layout-common.fill;
// Disable pointer events for the ripple container and state overlay because the container
// will overlay the user content and we don't want to disable mouse events on the user content.
// Pointer events can be safely disabled because the ripple trigger element is the host element.
pointer-events: none;
// Inherit the border radius from the parent so that state overlay and ripples don't exceed the
// parent button boundaries. Note that an inherited border radius does not work properly if
// the actual button element does have a border because it causes the inner content to be
// smaller. We have special logic for stroked buttons to handle this scenario.
border-radius: inherit;
}
// This style used to be applied by the MatRipple
// directive, which is no longer attached to this element.
.mat-mdc-button-ripple {
overflow: hidden;
}
// We use ::before so that we can reuse some of MDC's theming.
.mat-mdc-button-persistent-ripple::before {
content: '';
opacity: 0;
}
// The content should appear over the state and ripple layers, otherwise they may adversely affect
// the accessibility of the text content.
.mdc-button__label,
.mat-icon {
z-index: 1;
position: relative;
}
// The focus indicator should match the bounds of the entire button.
.mat-focus-indicator {
@include layout-common.fill();
}
&:focus .mat-focus-indicator::before {
content: '';
}
}
@mixin mat-private-button-ripple($prefix, $slots) {
@include token-utils.use-tokens($prefix, $slots) {
.mat-ripple-element {
@include token-utils.create-token-slot(background-color, ripple-color);
}
.mat-mdc-button-persistent-ripple::before {
@include token-utils.create-token-slot(background-color, state-layer-color);
}
&.mat-mdc-button-disabled .mat-mdc-button-persistent-ripple::before {
@include token-utils.create-token-slot(background-color, disabled-state-layer-color);
}
&:hover .mat-mdc-button-persistent-ripple::before {
@include token-utils.create-token-slot(opacity, hover-state-layer-opacity);
}
&.cdk-program-focused,
&.cdk-keyboard-focused,
&.mat-mdc-button-disabled-interactive:focus {
.mat-mdc-button-persistent-ripple::before {
@include token-utils.create-token-slot(opacity, focus-state-layer-opacity);
}
}
&:active .mat-mdc-button-persistent-ripple::before {
@include token-utils.create-token-slot(opacity, pressed-state-layer-opacity);
}
}
}
// MDC's disabled buttons define a default cursor with pointer-events none. However, they select
// :disabled for this, which does not affect anchor tags.
// TODO(andrewseguin): Discuss with the MDC team about a mixin we can call for applying this style,
// and note that having pointer-events may have unintended side-effects, e.g. allowing the user
// to click the target underneath the button.
@mixin mat-private-button-disabled() {
// `[disabled]` shouldn't be necessary, but we keep it to maintain
// compatibility with apps setting it through host bindings.
&[disabled],
&.mat-mdc-button-disabled {
cursor: default;
pointer-events: none;
@content;
}
&.mat-mdc-button-disabled-interactive {
pointer-events: auto;
}
}
// Adds an elevation shadow to a button.
@mixin mat-private-button-elevation($token-name) {
// MDC outputs a variable that is the same as the token name, but suffixed with `-shadow`.
box-shadow: token-utils.get-token-variable($token-name + '-shadow');
}
@mixin mat-private-button-touch-target($is-square, $prefix, $slots) {
.mat-mdc-button-touch-target {
position: absolute;
top: 50%;
height: 48px;
@if $is-square {
left: 50%;
width: 48px;
transform: translate(-50%, -50%);
} @else {
left: 0;
right: 0;
transform: translateY(-50%);
}
@include token-utils.use-tokens($prefix, $slots) {
@include token-utils.create-token-slot(display, touch-target-display);
}
}
}
@mixin mat-private-button-horizontal-layout($prefix, $slots, $has-with-icon-padding) {
@include token-utils.use-tokens($prefix, $slots) {
$icon-spacing: token-utils.get-token-variable(icon-spacing, true);
$icon-offset: token-utils.get-token-variable(icon-offset, true);
@if ($has-with-icon-padding) {
$with-icon-horizontal-padding:
token-utils.get-token-variable(with-icon-horizontal-padding, true);
// stylelint-disable-next-line selector-class-pattern
&:has(.material-icons, mat-icon, [matButtonIcon]) {
padding: 0 $with-icon-horizontal-padding;
}
}
// MDC expects button icons to contain this HTML content:
// ```html
// <span class="mdc-button__icon material-icons">favorite</span>
// ```
// However, Angular Material expects a `mat-icon` instead. The following
// styles will lay out the icons appropriately.
& > .mat-icon {
margin-right: $icon-spacing;
margin-left: $icon-offset;
[dir='rtl'] & {
margin-right: $icon-offset;
margin-left: $icon-spacing;
}
}
.mdc-button__label + .mat-icon {
margin-right: $icon-offset;
margin-left: $icon-spacing;
[dir='rtl'] & {
margin-right: $icon-spacing;
margin-left: $icon-offset;
}
}
}
}