| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575 |
- //
- // Copyright 2016 Google Inc.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- //
- // stylelint-disable selector-class-pattern --
- // Selector '.mdc-*' should only be used in this project.
- @use 'sass:map';
- @use '@material/density/functions' as density-functions;
- @use '@material/feature-targeting/feature-targeting';
- @use '@material/theme/theme';
- @use '@material/theme/keys';
- @use '@material/density/variables' as density-variables;
- @use '@material/theme/theme-color';
- @use '@material/ripple/ripple-theme';
- $ripple-size: 40px !default;
- $icon-size: 20px !default;
- $transition-duration: 120ms !default;
- $ripple-opacity: 0.14 !default;
- $baseline-theme-color: secondary !default;
- $unchecked-color: rgba(theme-color.prop-value(on-surface), 0.54) !default;
- $disabled-circle-color: rgba(theme-color.prop-value(on-surface), 0.38) !default;
- $minimum-size: 28px !default;
- $maximum-size: $ripple-size !default;
- $density-scale: density-variables.$default-scale !default;
- $density-config: (
- size: (
- minimum: $minimum-size,
- default: $ripple-size,
- maximum: $maximum-size,
- ),
- ) !default;
- $ripple-target: '.mdc-radio__ripple';
- $unselected-ripple-target: '.mdc-radio__native-control:enabled:not(:checked) ~ #{$ripple-target}';
- $custom-property-prefix: 'radio';
- // TODO(b/188417756): `icon-size` token key is not supported.
- $light-theme: (
- disabled-selected-icon-color: theme-color.$on-surface,
- disabled-selected-icon-opacity: 0.38,
- disabled-unselected-icon-color: theme-color.$on-surface,
- disabled-unselected-icon-opacity: 0.38,
- selected-focus-icon-color: theme-color.$primary,
- selected-focus-state-layer-color: theme-color.$primary,
- selected-focus-state-layer-opacity: 0.12,
- selected-hover-icon-color: theme-color.$primary,
- selected-hover-state-layer-color: theme-color.$primary,
- selected-hover-state-layer-opacity: 0.04,
- selected-icon-color: theme-color.$primary,
- selected-pressed-icon-color: theme-color.$primary,
- selected-pressed-state-layer-color: theme-color.$primary,
- selected-pressed-state-layer-opacity: 0.1,
- state-layer-size: $ripple-size,
- unselected-focus-icon-color: theme-color.$on-surface,
- unselected-focus-state-layer-color: theme-color.$on-surface,
- unselected-focus-state-layer-opacity: 0.12,
- unselected-hover-icon-color: theme-color.$on-surface,
- unselected-hover-state-layer-color: theme-color.$on-surface,
- unselected-hover-state-layer-opacity: 0.04,
- unselected-icon-color: theme-color.$on-surface,
- unselected-pressed-icon-color: theme-color.$on-surface,
- unselected-pressed-state-layer-color: theme-color.$on-surface,
- unselected-pressed-state-layer-opacity: 0.1,
- );
- @mixin theme($theme) {
- @include theme.validate-theme($light-theme, $theme);
- @include keys.declare-custom-properties(
- $theme,
- $prefix: $custom-property-prefix
- );
- }
- @mixin theme-styles($theme) {
- @include theme.validate-theme-styles($light-theme, $theme);
- $theme: keys.create-theme-properties(
- $theme,
- $prefix: $custom-property-prefix
- );
- @include _disabled-selected-icon-color(
- map.get($theme, disabled-selected-icon-color)
- );
- @include _disabled-selected-icon-opacity(
- map.get($theme, disabled-selected-icon-opacity)
- );
- @include _disabled-unselected-icon-color(
- map.get($theme, disabled-unselected-icon-color)
- );
- @include _disabled-unselected-icon-opacity(
- map.get($theme, disabled-unselected-icon-opacity)
- );
- // selected
- @include ripple-theme.focus() {
- @include _selected-icon-color(map.get($theme, selected-focus-icon-color));
- @include _selected-state-layer-color(
- map.get($theme, selected-focus-state-layer-color)
- );
- @include _selected-focus-state-layer-opacity(
- map.get($theme, selected-focus-state-layer-opacity)
- );
- }
- @include ripple-theme.hover() {
- @include _selected-icon-color(map.get($theme, selected-hover-icon-color));
- @include _selected-state-layer-color(
- map.get($theme, selected-hover-state-layer-color)
- );
- @include _selected-hover-state-layer-opacity(
- map.get($theme, selected-hover-state-layer-opacity)
- );
- }
- @include _selected-icon-color(map.get($theme, selected-icon-color));
- @include ripple-theme.active() {
- @include _selected-icon-color(map.get($theme, selected-pressed-icon-color));
- @include _selected-state-layer-color(
- map.get($theme, selected-pressed-state-layer-color)
- );
- @include _selected-pressed-state-layer-opacity(
- map.get($theme, selected-pressed-state-layer-opacity)
- );
- }
- // unselected
- @include ripple-theme.focus() {
- @include _unselected-icon-color(
- map.get($theme, unselected-focus-icon-color)
- );
- @include _unselected-state-layer-color(
- map.get($theme, unselected-focus-state-layer-color)
- );
- @include _unselected-focus-state-layer-opacity(
- map.get($theme, unselected-focus-state-layer-opacity)
- );
- }
- @include ripple-theme.hover() {
- @include _unselected-icon-color(
- map.get($theme, unselected-hover-icon-color)
- );
- @include _unselected-state-layer-color(
- map.get($theme, unselected-hover-state-layer-color)
- );
- @include _unselected-hover-state-layer-opacity(
- map.get($theme, unselected-hover-state-layer-opacity)
- );
- }
- @include _unselected-icon-color(map.get($theme, unselected-icon-color));
- @include ripple-theme.active() {
- @include _unselected-icon-color(
- map.get($theme, unselected-pressed-icon-color)
- );
- @include _unselected-state-layer-color(
- map.get($theme, unselected-pressed-state-layer-color)
- );
- @include _unselected-pressed-state-layer-opacity(
- map.get($theme, unselected-pressed-state-layer-opacity)
- );
- }
- @include ripple-size(map.get($theme, state-layer-size));
- // Set touch target size same as ripple size.
- @include touch-target(
- $size: map.get($theme, state-layer-size),
- $ripple-size: map.get($theme, state-layer-size)
- );
- }
- @mixin _disabled-selected-icon-color($color) {
- @include disabled-checked-stroke-color($color);
- @include disabled-ink-color($color);
- }
- @mixin _disabled-selected-icon-opacity($opacity) {
- @include _disabled-checked-stroke-opacity($opacity);
- @include _disabled-ink-opacity($opacity);
- }
- @mixin _disabled-unselected-icon-color($color) {
- @include disabled-unchecked-stroke-color($color);
- }
- @mixin _disabled-unselected-icon-opacity($opacity) {
- @include _disabled-unchecked-stroke-opacity($opacity);
- }
- @mixin _selected-icon-color($color) {
- @include checked-stroke-color($color);
- @include ink-color($color);
- }
- @mixin _selected-state-layer-color($color) {
- @include ripple-theme.states-base-color(
- $color: $color,
- $ripple-target: $ripple-target
- );
- }
- @mixin _selected-hover-state-layer-opacity($opacity) {
- @include ripple-theme.states-hover-opacity(
- $opacity: $opacity,
- $ripple-target: $ripple-target
- );
- }
- @mixin _selected-focus-state-layer-opacity($opacity) {
- @include ripple-theme.states-focus-opacity(
- $opacity: $opacity,
- $ripple-target: $ripple-target
- );
- }
- @mixin _selected-pressed-state-layer-opacity($opacity) {
- @include ripple-theme.states-press-opacity(
- $opacity: $opacity,
- $ripple-target: $ripple-target
- );
- }
- @mixin _unselected-icon-color($color) {
- @include unchecked-stroke-color($color);
- }
- @mixin _unselected-state-layer-color($color) {
- @include ripple-theme.states-base-color(
- $color: $color,
- $ripple-target: $unselected-ripple-target
- );
- }
- @mixin _unselected-hover-state-layer-opacity($opacity) {
- @include ripple-theme.states-hover-opacity(
- $opacity: $opacity,
- $ripple-target: $unselected-ripple-target
- );
- }
- @mixin _unselected-focus-state-layer-opacity($opacity) {
- @include ripple-theme.states-focus-opacity(
- $opacity: $opacity,
- $ripple-target: $unselected-ripple-target
- );
- }
- @mixin _unselected-pressed-state-layer-opacity($opacity) {
- @include ripple-theme.states-press-opacity(
- $opacity: $opacity,
- $ripple-target: $unselected-ripple-target
- );
- }
- ///
- /// Sets the stroke color of an unchecked, enabled radio button.
- /// @param {Color} $color - The desired stroke color.
- ///
- @mixin unchecked-stroke-color($color, $query: feature-targeting.all()) {
- @include _if-enabled-unchecked {
- @include _stroke-color($color, $query: $query);
- }
- }
- ///
- /// Sets the stroke color of a checked, enabled radio button.
- /// @param {Color} $color - The desired stroke color.
- ///
- @mixin checked-stroke-color($color, $query: feature-targeting.all()) {
- @include _if-enabled-checked {
- @include _stroke-color($color, $query: $query);
- }
- }
- ///
- /// Sets the ink color of an enabled radio button.
- /// @param {Color} $color - The desired ink color.
- ///
- @mixin ink-color($color, $query: feature-targeting.all()) {
- @include _if-enabled {
- @include _ink-color($color, $query: $query);
- }
- }
- ///
- /// Sets the stroke color of an unchecked, disabled radio button.
- /// @param {Color} $color - The desired stroke color.
- ///
- @mixin disabled-unchecked-stroke-color(
- $color,
- $query: feature-targeting.all()
- ) {
- @include _if-disabled-unchecked {
- @include _stroke-color($color, $query: $query);
- }
- }
- @mixin _disabled-unchecked-stroke-opacity($opacity) {
- @include _if-disabled-unchecked {
- @include _stroke-opacity($opacity);
- }
- }
- ///
- /// Sets the stroke color of a checked, disabled radio button.
- /// @param {Color} $color - The desired stroke color.
- ///
- @mixin disabled-checked-stroke-color($color, $query: feature-targeting.all()) {
- @include if-disabled-checked_ {
- @include _stroke-color($color, $query: $query);
- }
- }
- @mixin _disabled-checked-stroke-opacity($opacity) {
- @include if-disabled-checked_ {
- @include _stroke-opacity($opacity);
- }
- }
- ///
- /// Sets the ink color of a disabled radio button.
- /// @param {Color} $color - The desired ink color
- ///
- @mixin disabled-ink-color($color, $query: feature-targeting.all()) {
- @include if-disabled_ {
- @include _ink-color($color, $query: $query);
- }
- }
- @mixin _disabled-ink-opacity($opacity) {
- @include if-disabled_ {
- @include _ink-opacity($opacity);
- }
- }
- @mixin focus-indicator-color($color, $query: feature-targeting.all()) {
- $feat-color: feature-targeting.create-target($query, color);
- .mdc-radio__background::before {
- @include feature-targeting.targets($feat-color) {
- @include theme.property(background-color, $color);
- }
- }
- }
- ///
- /// Sets radio touch target size which can be more than the ripple size. Param `$ripple-size` is required for custom
- /// ripple size.
- ///
- /// @param {Number} $size Size of touch target (Native input) in `px`.
- /// @param {Number} $ripple-size Size of ripple in `px`. Required only for custom ripple size.
- ///
- @mixin touch-target(
- $size: $ripple-size,
- $ripple-size: $ripple-size,
- $query: feature-targeting.all()
- ) {
- $feat-structure: feature-targeting.create-target($query, structure);
- $offset: 'calc((__ripple_size - __size) / 2)';
- $replace: (
- __ripple_size: $ripple-size,
- __size: $size,
- );
- .mdc-radio__native-control {
- @include feature-targeting.targets($feat-structure) {
- @include theme.property('top', $offset, $replace: $replace);
- @include theme.property('right', $offset, $replace: $replace);
- @include theme.property('left', $offset, $replace: $replace);
- @include theme.property('width', $size);
- @include theme.property('height', $size);
- }
- }
- }
- ///
- /// Sets density scale for radio.
- ///
- /// @param {Number | String} $density-scale - Density scale value for component. Supported density scale values
- /// `-3`, `-2`, `-1`, `0`.
- ///
- @mixin density($density-scale, $query: feature-targeting.all()) {
- $size: density-functions.prop-value(
- $density-config: $density-config,
- $density-scale: $density-scale,
- $property-name: size,
- );
- @include ripple-size($size, $query: $query);
- // Sets touch target size same as ripple size.
- @include touch-target($size: $size, $ripple-size: $size, $query: $query);
- @if $density-scale != 0 {
- @include touch-target-reset_($query: $query);
- }
- }
- ///
- /// Sets radio ripple size.
- ///
- /// @param {Number} $size - Ripple size in `px`.
- ///
- @mixin ripple-size($size, $query: feature-targeting.all()) {
- $feat-structure: feature-targeting.create-target($query, structure);
- $replace: (
- __size: $size,
- __icon_size: $icon-size,
- );
- @include feature-targeting.targets($feat-structure) {
- $padding: 'calc((__size - __icon_size) / 2)';
- @include theme.property('padding', $padding, $replace: $replace);
- }
- .mdc-radio__background::before {
- @include feature-targeting.targets($feat-structure) {
- $padding-offset: 'calc(-1 * (__size - __icon_size) / 2)';
- @include theme.property('top', $padding-offset, $replace: $replace);
- @include theme.property('left', $padding-offset, $replace: $replace);
- @include theme.property('width', $size);
- @include theme.property('height', $size);
- }
- }
- }
- ///
- /// Resets touch target-related styles. This is called from the density mixin to
- /// automatically remove the increased touch target, since dense components
- /// don't have the same default a11y requirements.
- /// @access private
- ///
- @mixin touch-target-reset_($query: feature-targeting.all()) {
- $feat-structure: feature-targeting.create-target($query, structure);
- @include feature-targeting.targets($feat-structure) {
- margin: 0;
- }
- }
- ///
- /// Helps select the radio background only when its native control is in the
- /// enabled state.
- /// @access private
- ///
- @mixin _if-enabled {
- .mdc-radio__native-control:enabled + {
- @content;
- }
- }
- ///
- /// Helps select the radio background only when its native control is in the
- /// enabled & unchecked state.
- /// @access private
- ///
- @mixin _if-enabled-unchecked {
- .mdc-radio__native-control:enabled:not(:checked) + {
- @content;
- }
- }
- ///
- /// Helps select the radio background only when its native control is in the
- /// enabled & checked state.
- /// @access private
- ///
- @mixin _if-enabled-checked {
- .mdc-radio__native-control:enabled:checked + {
- @content;
- }
- }
- ///
- /// Helps select the radio background only when its native control is in the
- /// disabled state.
- /// @access private
- ///
- @mixin if-disabled_ {
- [aria-disabled='true'] .mdc-radio__native-control,
- .mdc-radio__native-control:disabled {
- + {
- @content;
- }
- }
- }
- ///
- /// Helps select the radio background only when its native control is in the
- /// disabled & unchecked state.
- /// @access private
- ///
- @mixin _if-disabled-unchecked {
- [aria-disabled='true'] .mdc-radio__native-control,
- .mdc-radio__native-control:disabled {
- &:not(:checked) + {
- @content;
- }
- }
- }
- ///
- /// Helps select the radio background only when its native control is in the
- /// disabled & checked state.
- /// @access private
- ///
- @mixin if-disabled-checked_ {
- [aria-disabled='true'] .mdc-radio__native-control,
- .mdc-radio__native-control:disabled {
- &:checked + {
- @content;
- }
- }
- }
- ///
- /// Sets the ink color for radio. This is wrapped in a mixin
- /// that qualifies state such as `_if-enabled`
- /// @access private
- ///
- @mixin _ink-color($color, $query: feature-targeting.all()) {
- $feat-color: feature-targeting.create-target($query, color);
- .mdc-radio__background .mdc-radio__inner-circle {
- @include feature-targeting.targets($feat-color) {
- @include theme.property(border-color, $color);
- }
- }
- }
- @mixin _ink-opacity($opacity) {
- .mdc-radio__background .mdc-radio__inner-circle {
- @include theme.property(opacity, $opacity);
- }
- }
- ///
- /// Sets the stroke color for radio. This is wrapped in a mixin
- /// that qualifies state such as `_if-enabled`
- /// @access private
- ///
- @mixin _stroke-color($color, $query: feature-targeting.all()) {
- $feat-color: feature-targeting.create-target($query, color);
- .mdc-radio__background .mdc-radio__outer-circle {
- @include feature-targeting.targets($feat-color) {
- @include theme.property(border-color, $color);
- }
- }
- }
- @mixin _stroke-opacity($opacity) {
- .mdc-radio__background .mdc-radio__outer-circle {
- @include theme.property(opacity, $opacity);
- }
- }
|