@use '../core/tokens/m2/mdc/radio' as tokens-mdc-radio; @use '../core/tokens/token-utils'; $_icon-size: 20px; @function _enter-transition($name) { @return $name 90ms cubic-bezier(0, 0, 0.2, 1); } @function _exit-transition($name) { @return $name 90ms cubic-bezier(0.4, 0, 0.6, 1); } // Structural styles for a radio button. Shared with the selection list. @mixin radio-structure($is-interactive) { $tokens: tokens-mdc-radio.$prefix, tokens-mdc-radio.get-token-slots(); .mdc-radio { display: inline-block; position: relative; flex: 0 0 auto; box-sizing: content-box; width: $_icon-size; height: $_icon-size; cursor: pointer; // This is something we inherited from MDC, but it shouldn't be necessary. // Removing it will likely lead to screenshot diffs. will-change: opacity, transform, border-color, color; @include token-utils.use-tokens($tokens...) { $size-token: token-utils.get-token-variable(state-layer-size); padding: calc((#{$size-token} - #{$_icon-size}) / 2); } @if ($is-interactive) { // MDC's hover indication comes from their ripple which we don't use. &:hover > .mdc-radio__native-control:not([disabled]):not(:focus) { & ~ .mdc-radio__background::before { opacity: 0.04; transform: scale(1); } } &:hover > .mdc-radio__native-control:not([disabled]) ~ .mdc-radio__background { > .mdc-radio__outer-circle { @include token-utils.use-tokens($tokens...) { @include token-utils.create-token-slot(border-color, unselected-hover-icon-color); } } } &:hover > .mdc-radio__native-control:enabled:checked + .mdc-radio__background { > .mdc-radio__outer-circle, > .mdc-radio__inner-circle { @include token-utils.use-tokens($tokens...) { @include token-utils.create-token-slot(border-color, selected-hover-icon-color); } } } &:active > .mdc-radio__native-control:enabled:not(:checked) + .mdc-radio__background { > .mdc-radio__outer-circle { @include token-utils.use-tokens($tokens...) { @include token-utils.create-token-slot(border-color, unselected-pressed-icon-color); } } } &:active > .mdc-radio__native-control:enabled:checked + .mdc-radio__background { > .mdc-radio__outer-circle, > .mdc-radio__inner-circle { @include token-utils.use-tokens($tokens...) { @include token-utils.create-token-slot(border-color, selected-pressed-icon-color); } } } } } .mdc-radio__background { display: inline-block; position: relative; box-sizing: border-box; width: $_icon-size; height: $_icon-size; &::before { position: absolute; transform: scale(0, 0); border-radius: 50%; opacity: 0; pointer-events: none; content: ''; transition: _exit-transition(opacity), _exit-transition(transform); @include token-utils.use-tokens($tokens...) { $size: token-utils.get-token-variable(state-layer-size); $offset: calc(-1 * (#{$size} - #{$_icon-size}) / 2); width: $size; height: $size; top: $offset; left: $offset; } } } .mdc-radio__outer-circle { position: absolute; top: 0; left: 0; box-sizing: border-box; width: 100%; height: 100%; border-width: 2px; border-style: solid; border-radius: 50%; transition: _exit-transition(border-color); } .mdc-radio__inner-circle { position: absolute; top: 0; left: 0; box-sizing: border-box; width: 100%; height: 100%; transform: scale(0, 0); border-width: 10px; border-style: solid; border-radius: 50%; transition: _exit-transition(transform), _exit-transition(border-color); } .mdc-radio__native-control { position: absolute; margin: 0; padding: 0; opacity: 0; top: 0; right: 0; left: 0; cursor: inherit; z-index: 1; @include token-utils.use-tokens($tokens...) { @include token-utils.create-token-slot(width, state-layer-size); @include token-utils.create-token-slot(height, state-layer-size); } &:checked, &:disabled { + .mdc-radio__background { transition: _enter-transition(opacity), _enter-transition(transform); > .mdc-radio__outer-circle { transition: _enter-transition(border-color); } > .mdc-radio__inner-circle { transition: _enter-transition(transform), _enter-transition(border-color); } } } @if ($is-interactive) { &:focus + .mdc-radio__background::before { transform: scale(1); opacity: 0.12; transition: _enter-transition(opacity), _enter-transition(transform); } } &:disabled { @include token-utils.use-tokens($tokens...) { &:not(:checked) + .mdc-radio__background > .mdc-radio__outer-circle { @include token-utils.create-token-slot(border-color, disabled-unselected-icon-color); @include token-utils.create-token-slot(opacity, disabled-unselected-icon-opacity); } + .mdc-radio__background { cursor: default; > .mdc-radio__inner-circle, > .mdc-radio__outer-circle { @include token-utils.create-token-slot(border-color, disabled-selected-icon-color); @include token-utils.create-token-slot(opacity, disabled-selected-icon-opacity); } } } } &:enabled { @include token-utils.use-tokens($tokens...) { &:not(:checked) + .mdc-radio__background > .mdc-radio__outer-circle { @include token-utils.create-token-slot(border-color, unselected-icon-color); } &:checked + .mdc-radio__background { > .mdc-radio__outer-circle, > .mdc-radio__inner-circle { @include token-utils.create-token-slot(border-color, selected-icon-color); } } @if ($is-interactive) { &:focus:checked + .mdc-radio__background { > .mdc-radio__inner-circle, > .mdc-radio__outer-circle { @include token-utils.create-token-slot(border-color, selected-focus-icon-color); } } } } } &:checked + .mdc-radio__background > .mdc-radio__inner-circle { transform: scale(0.5); transition: _enter-transition(transform), _enter-transition(border-color); } } @if ($is-interactive) { &.mat-mdc-radio-disabled-interactive .mdc-radio--disabled { pointer-events: auto; @include token-utils.use-tokens($tokens...) { // stylelint-disable selector-combinator-space-before .mdc-radio__native-control:not(:checked) + .mdc-radio__background > .mdc-radio__outer-circle { @include token-utils.create-token-slot(border-color, disabled-unselected-icon-color); @include token-utils.create-token-slot(opacity, disabled-unselected-icon-opacity); } // stylelint-enable selector-combinator-space-before &:hover .mdc-radio__native-control:checked + .mdc-radio__background, .mdc-radio__native-control:checked:focus + .mdc-radio__background, .mdc-radio__native-control + .mdc-radio__background { > .mdc-radio__inner-circle, > .mdc-radio__outer-circle { @include token-utils.create-token-slot(border-color, disabled-selected-icon-color); @include token-utils.create-token-slot(opacity, disabled-selected-icon-opacity); } } } } } } // Conditionally disables the animations of the radio button. @mixin radio-noop-animations() { &._mat-animation-noopable { .mdc-radio__background::before, .mdc-radio__outer-circle, .mdc-radio__inner-circle { // Needs to be `!important`, because MDC's selectors are really specific. transition: none !important; } } }