diff --git a/src/material/checkbox/_checkbox-common.scss b/src/material/checkbox/_checkbox-common.scss new file mode 100644 index 000000000000..723688198a98 --- /dev/null +++ b/src/material/checkbox/_checkbox-common.scss @@ -0,0 +1,509 @@ +@use 'sass:math'; +@use '@angular/cdk'; +@use '../core/tokens/m2/mdc/checkbox' as tokens-mdc-checkbox; +@use '../core/tokens/token-utils'; + +$_path-length: 29.7833385; +$_transition-duration: 90ms; +$_icon-size: 18px; +$_mark-stroke-size: math.div(2, 15) * $_icon-size; +$_indeterminate-checked-curve: cubic-bezier(0.14, 0, 0, 1); +$_indeterminate-change-duration: 500ms; +$_enter-curve: cubic-bezier(0, 0, 0.2, 1); +$_exit-curve: cubic-bezier(0.4, 0, 0.6, 1); + +// Structural styles for a checkbox. To be shared with the selection list. +@mixin checkbox-structure($include-state-layer-styles) { + $prefix: tokens-mdc-checkbox.$prefix; + $slots: tokens-mdc-checkbox.get-token-slots(); + $layer-size: token-utils.get-token-variable(state-layer-size); + + .mdc-checkbox { + display: inline-block; + position: relative; + flex: 0 0 $_icon-size; + box-sizing: content-box; + width: $_icon-size; + height: $_icon-size; + line-height: 0; + white-space: nowrap; + cursor: pointer; + vertical-align: bottom; + + @include token-utils.use-tokens($prefix, $slots) { + padding: calc((var(#{$layer-size}) - #{$_icon-size}) / 2); + margin: calc((var(#{$layer-size}) - var(#{$layer-size})) / 2); + + @if ($include-state-layer-styles) { + @include _state-layer-styles; + } + } + + // These styles have to be nested in order to override overly-broad + // user selectors like `input[type='checkbox']`. + .mdc-checkbox__native-control { + position: absolute; + margin: 0; + padding: 0; + opacity: 0; + cursor: inherit; + + @include token-utils.use-tokens($prefix, $slots) { + @include token-utils.create-token-slot(width, state-layer-size); + @include token-utils.create-token-slot(height, state-layer-size); + top: calc((var(#{$layer-size}) - var(#{$layer-size})) / 2); + right: calc((var(#{$layer-size}) - var(#{$layer-size})) / 2); + left: calc((var(#{$layer-size}) - var(#{$layer-size})) / 2); + } + } + } + + ._mat-animation-noopable .mdc-checkbox { + *, + *::before { + transition: none !important; + animation: none !important; + } + } + + .mdc-checkbox--disabled { + cursor: default; + pointer-events: none; + } + + .mdc-checkbox__background { + display: inline-flex; + position: absolute; + align-items: center; + justify-content: center; + box-sizing: border-box; + width: $_icon-size; + height: $_icon-size; + border: 2px solid currentColor; + border-radius: 2px; + background-color: transparent; + pointer-events: none; + will-change: background-color, border-color; + transition: background-color $_transition-duration $_exit-curve, + border-color $_transition-duration $_exit-curve; + + @include token-utils.use-tokens($prefix, $slots) { + @include token-utils.create-token-slot(border-color, unselected-icon-color); + top: calc((var(#{$layer-size}) - #{$_icon-size}) / 2); + left: calc((var(#{$layer-size}) - #{$_icon-size}) / 2); + } + } + + // These can't be under `.mdc-checkbox__background` because + // the selectors will break when the mixin is nested. + @include token-utils.use-tokens($prefix, $slots) { + .mdc-checkbox__native-control:enabled:checked ~ .mdc-checkbox__background, + .mdc-checkbox__native-control:enabled:indeterminate ~ .mdc-checkbox__background { + @include token-utils.create-token-slot(border-color, selected-icon-color); + @include token-utils.create-token-slot(background-color, selected-icon-color); + } + + .mdc-checkbox--disabled .mdc-checkbox__background { + @include token-utils.create-token-slot(border-color, disabled-unselected-icon-color); + } + + .mdc-checkbox__native-control:disabled:checked ~ .mdc-checkbox__background, + .mdc-checkbox__native-control:disabled:indeterminate ~ .mdc-checkbox__background { + @include token-utils.create-token-slot(background-color, disabled-selected-icon-color); + border-color: transparent; + } + + .mdc-checkbox:hover .mdc-checkbox__native-control:not(:checked) ~ .mdc-checkbox__background, + .mdc-checkbox:hover + .mdc-checkbox__native-control:not(:indeterminate) ~ .mdc-checkbox__background { + @include token-utils.create-token-slot(border-color, unselected-hover-icon-color); + } + + .mdc-checkbox:hover .mdc-checkbox__native-control:checked ~ .mdc-checkbox__background, + .mdc-checkbox:hover .mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background { + @include token-utils.create-token-slot(border-color, selected-hover-icon-color); + } + + // Note: this must be more specific than the hover styles above. + .mdc-checkbox__native-control:focus:not(:checked) ~ .mdc-checkbox__background, + .mdc-checkbox__native-control:focus:not(:indeterminate) ~ .mdc-checkbox__background { + @include token-utils.create-token-slot(border-color, unselected-focus-icon-color); + } + + .mdc-checkbox__native-control:focus:checked ~ .mdc-checkbox__background, + .mdc-checkbox__native-control:focus:indeterminate ~ .mdc-checkbox__background { + @include token-utils.create-token-slot(border-color, selected-focus-icon-color); + } + } + + .mdc-checkbox__checkmark { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + width: 100%; + opacity: 0; + transition: opacity $_transition-duration * 2 $_exit-curve; + + @include token-utils.use-tokens($prefix, $slots) { + // Always apply the color since the element becomes `opacity: 0` + // when unchecked. This makes the animation look better. + @include token-utils.create-token-slot(color, selected-checkmark-color); + } + } + + @include token-utils.use-tokens($prefix, $slots) { + .mdc-checkbox--disabled .mdc-checkbox__checkmark { + @include token-utils.create-token-slot(color, disabled-selected-checkmark-color); + } + } + + .mdc-checkbox__checkmark-path { + transition: stroke-dashoffset $_transition-duration * 2 $_exit-curve; + stroke: currentColor; + stroke-width: $_mark-stroke-size * 1.3; + stroke-dashoffset: $_path-length; + stroke-dasharray: $_path-length; + } + + .mdc-checkbox__mixedmark { + width: 100%; + height: 0; + transform: scaleX(0) rotate(0deg); + border-width: math.div(math.floor($_mark-stroke-size), 2); + border-style: solid; + opacity: 0; + transition: opacity $_transition-duration $_exit-curve, + transform $_transition-duration $_exit-curve; + + @include cdk.high-contrast(active, off) { + margin: 0 1px; + } + + @include token-utils.use-tokens($prefix, $slots) { + // Always apply the color since the element becomes `opacity: 0` + // when unchecked. This makes the animation look better. + @include token-utils.create-token-slot(border-color, selected-checkmark-color); + } + } + + @include token-utils.use-tokens($prefix, $slots) { + .mdc-checkbox--disabled .mdc-checkbox__mixedmark { + @include token-utils.create-token-slot(border-color, disabled-selected-checkmark-color); + } + } + + .mdc-checkbox--anim-unchecked-checked, + .mdc-checkbox--anim-unchecked-indeterminate, + .mdc-checkbox--anim-checked-unchecked, + .mdc-checkbox--anim-indeterminate-unchecked { + .mdc-checkbox__background { + animation-duration: $_transition-duration * 2; + animation-timing-function: linear; + } + } + + .mdc-checkbox--anim-unchecked-checked { + .mdc-checkbox__checkmark-path { + animation: mdc-checkbox-unchecked-checked-checkmark-path + $_transition-duration * 2 linear; + transition: none; + } + } + + .mdc-checkbox--anim-unchecked-indeterminate { + .mdc-checkbox__mixedmark { + animation: mdc-checkbox-unchecked-indeterminate-mixedmark $_transition-duration linear; + transition: none; + } + } + + .mdc-checkbox--anim-checked-unchecked { + .mdc-checkbox__checkmark-path { + animation: mdc-checkbox-checked-unchecked-checkmark-path $_transition-duration linear; + transition: none; + } + } + + .mdc-checkbox--anim-checked-indeterminate { + .mdc-checkbox__checkmark { + animation: mdc-checkbox-checked-indeterminate-checkmark $_transition-duration linear; + transition: none; + } + + .mdc-checkbox__mixedmark { + animation: mdc-checkbox-checked-indeterminate-mixedmark $_transition-duration linear; + transition: none; + } + } + + .mdc-checkbox--anim-indeterminate-checked { + .mdc-checkbox__checkmark { + animation: mdc-checkbox-indeterminate-checked-checkmark + $_indeterminate-change-duration linear; + transition: none; + } + + .mdc-checkbox__mixedmark { + animation: mdc-checkbox-indeterminate-checked-mixedmark + $_indeterminate-change-duration linear; + transition: none; + } + } + + .mdc-checkbox--anim-indeterminate-unchecked { + .mdc-checkbox__mixedmark { + animation: mdc-checkbox-indeterminate-unchecked-mixedmark + $_indeterminate-change-duration * 0.6 linear; + transition: none; + } + } + + .mdc-checkbox__native-control:checked ~ .mdc-checkbox__background, + .mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background { + transition: border-color $_transition-duration $_enter-curve, + background-color $_transition-duration $_enter-curve; + + .mdc-checkbox__checkmark-path { + stroke-dashoffset: 0; + } + } + + .mdc-checkbox__native-control:checked ~ .mdc-checkbox__background { + .mdc-checkbox__checkmark { + transition: opacity $_transition-duration * 2 $_enter-curve, + transform $_transition-duration * 2 $_enter-curve; + opacity: 1; + } + + .mdc-checkbox__mixedmark { + transform: scaleX(1) rotate(-45deg); + } + } + .mdc-checkbox__native-control:indeterminate ~ .mdc-checkbox__background { + .mdc-checkbox__checkmark { + transform: rotate(45deg); + opacity: 0; + transition: opacity $_transition-duration $_exit-curve, + transform $_transition-duration $_exit-curve; + } + + .mdc-checkbox__mixedmark { + transform: scaleX(1) rotate(0deg); + opacity: 1; + } + } + + @keyframes mdc-checkbox-unchecked-checked-checkmark-path { + 0%, 50% { + stroke-dashoffset: $_path-length; + } + + 50% { + animation-timing-function: $_enter-curve; + } + + 100% { + stroke-dashoffset: 0; + } + } + + @keyframes mdc-checkbox-unchecked-indeterminate-mixedmark { + 0%, 68.2% { + transform: scaleX(0); + } + + 68.2% { + animation-timing-function: cubic-bezier(0, 0, 0, 1); + } + + 100% { + transform: scaleX(1); + } + } + + @keyframes mdc-checkbox-checked-unchecked-checkmark-path { + from { + animation-timing-function: cubic-bezier(0.4, 0, 1, 1); + opacity: 1; + stroke-dashoffset: 0; + } + + to { + opacity: 0; + stroke-dashoffset: $_path-length * -1; + } + } + + @keyframes mdc-checkbox-checked-indeterminate-checkmark { + from { + animation-timing-function: $_enter-curve; + transform: rotate(0deg); + opacity: 1; + } + + to { + transform: rotate(45deg); + opacity: 0; + } + } + + @keyframes mdc-checkbox-indeterminate-checked-checkmark { + from { + animation-timing-function: $_indeterminate-checked-curve; + transform: rotate(45deg); + opacity: 0; + } + + to { + transform: rotate(360deg); + opacity: 1; + } + } + + @keyframes mdc-checkbox-checked-indeterminate-mixedmark { + from { + animation-timing-function: $_enter-curve; + transform: rotate(-45deg); + opacity: 0; + } + + to { + transform: rotate(0deg); + opacity: 1; + } + } + + @keyframes mdc-checkbox-indeterminate-checked-mixedmark { + from { + animation-timing-function: $_indeterminate-checked-curve; + transform: rotate(0deg); + opacity: 1; + } + + to { + transform: rotate(315deg); + opacity: 0; + } + } + + @keyframes mdc-checkbox-indeterminate-unchecked-mixedmark { + 0% { + animation-timing-function: linear; + transform: scaleX(1); + opacity: 1; + } + + 32.8%, 100% { + transform: scaleX(0); + opacity: 0; + } + } +} + +@mixin _state-layer-styles() { + // MDC expects `.mdc-checkbox__ripple::before` to be the state layer, but we use + // `.mdc-checkbox__ripple` instead, so we emit the state layer slots ourselves. + &:hover { + .mdc-checkbox__ripple { + @include token-utils.create-token-slot(opacity, unselected-hover-state-layer-opacity); + @include token-utils.create-token-slot( + background-color, + unselected-hover-state-layer-color + ); + } + + .mat-mdc-checkbox-ripple .mat-ripple-element { + @include token-utils.create-token-slot( + background-color, + unselected-hover-state-layer-color + ); + } + } + + .mdc-checkbox__native-control:focus { + & ~ .mdc-checkbox__ripple { + @include token-utils.create-token-slot(opacity, unselected-focus-state-layer-opacity); + @include token-utils.create-token-slot( + background-color, + unselected-focus-state-layer-color + ); + } + + & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { + @include token-utils.create-token-slot( + background-color, + unselected-focus-state-layer-color + ); + } + } + + &:active .mdc-checkbox__native-control { + & ~ .mdc-checkbox__ripple { + @include token-utils.create-token-slot(opacity, unselected-pressed-state-layer-opacity); + @include token-utils.create-token-slot( + background-color, + unselected-pressed-state-layer-color + ); + } + + & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { + @include token-utils.create-token-slot( + background-color, + unselected-pressed-state-layer-color + ); + } + } + + &:hover .mdc-checkbox__native-control:checked { + & ~ .mdc-checkbox__ripple { + @include token-utils.create-token-slot(opacity, selected-hover-state-layer-opacity); + @include token-utils.create-token-slot( + background-color, + selected-hover-state-layer-color + ); + } + + & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { + @include token-utils.create-token-slot( + background-color, + selected-hover-state-layer-color + ); + } + } + + .mdc-checkbox__native-control:focus:checked { + & ~ .mdc-checkbox__ripple { + @include token-utils.create-token-slot(opacity, selected-focus-state-layer-opacity); + @include token-utils.create-token-slot( + background-color, + selected-focus-state-layer-color + ); + } + + & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { + @include token-utils.create-token-slot( + background-color, + selected-focus-state-layer-color + ); + } + } + + &:active .mdc-checkbox__native-control:checked { + & ~ .mdc-checkbox__ripple { + @include token-utils.create-token-slot(opacity, selected-pressed-state-layer-opacity); + @include token-utils.create-token-slot( + background-color, + selected-pressed-state-layer-color + ); + } + + & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { + @include token-utils.create-token-slot( + background-color, + selected-pressed-state-layer-color + ); + } + } +} diff --git a/src/material/checkbox/_checkbox-theme.scss b/src/material/checkbox/_checkbox-theme.scss index 6835ef515eae..13d106a71781 100644 --- a/src/material/checkbox/_checkbox-theme.scss +++ b/src/material/checkbox/_checkbox-theme.scss @@ -1,4 +1,3 @@ -@use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme; @use '../core/style/sass-utils'; @use '../core/theming/theming'; @use '../core/theming/inspection'; @@ -16,7 +15,10 @@ @include _theme-from-tokens(inspection.get-theme-tokens($theme, base)); } @else { @include sass-utils.current-selector-or-root() { - @include mdc-checkbox-theme.theme(tokens-mdc-checkbox.get-unthemable-tokens()); + @include token-utils.create-token-values( + tokens-mdc-checkbox.$prefix, + tokens-mdc-checkbox.get-unthemable-tokens() + ); @include token-utils.create-token-values( tokens-mat-checkbox.$prefix, tokens-mat-checkbox.get-unthemable-tokens() @@ -35,7 +37,10 @@ @include _theme-from-tokens(inspection.get-theme-tokens($theme, color), $options...); } @else { @include sass-utils.current-selector-or-root() { - @include mdc-checkbox-theme.theme(tokens-mdc-checkbox.get-color-tokens($theme)); + @include token-utils.create-token-values( + tokens-mdc-checkbox.$prefix, + tokens-mdc-checkbox.get-color-tokens($theme) + ); @include token-utils.create-token-values( tokens-mat-checkbox.$prefix, tokens-mat-checkbox.get-color-tokens($theme) @@ -44,11 +49,15 @@ .mat-mdc-checkbox { &.mat-primary { - @include mdc-checkbox-theme.theme(tokens-mdc-checkbox.get-color-tokens($theme, primary)); + @include token-utils.create-token-values( + tokens-mdc-checkbox.$prefix, + tokens-mdc-checkbox.get-color-tokens($theme, primary)); } &.mat-warn { - @include mdc-checkbox-theme.theme(tokens-mdc-checkbox.get-color-tokens($theme, warn)); + @include token-utils.create-token-values( + tokens-mdc-checkbox.$prefix, + tokens-mdc-checkbox.get-color-tokens($theme, warn)); } } } @@ -61,7 +70,10 @@ @include _theme-from-tokens(inspection.get-theme-tokens($theme, typography)); } @else { @include sass-utils.current-selector-or-root() { - @include mdc-checkbox-theme.theme(tokens-mdc-checkbox.get-typography-tokens($theme)); + @include token-utils.create-token-values( + tokens-mdc-checkbox.$prefix, + tokens-mdc-checkbox.get-typography-tokens($theme) + ); @include token-utils.create-token-values( tokens-mat-checkbox.$prefix, tokens-mat-checkbox.get-typography-tokens($theme) @@ -79,7 +91,10 @@ @include _theme-from-tokens(inspection.get-theme-tokens($theme, density)); } @else { @include sass-utils.current-selector-or-root() { - @include mdc-checkbox-theme.theme(tokens-mdc-checkbox.get-density-tokens($theme)); + @include token-utils.create-token-values( + tokens-mdc-checkbox.$prefix, + tokens-mdc-checkbox.get-density-tokens($theme) + ); @include token-utils.create-token-values( tokens-mat-checkbox.$prefix, tokens-mat-checkbox.get-density-tokens($theme) @@ -140,6 +155,6 @@ // Don't pass $options here, since the mdc-checkbox doesn't support color options, // only the mdc-checkbox does. $mat-checkbox-tokens: token-utils.get-tokens-for($tokens, tokens-mat-checkbox.$prefix); - @include mdc-checkbox-theme.theme($mdc-checkbox-tokens); + @include token-utils.create-token-values(tokens-mdc-checkbox.$prefix, $mdc-checkbox-tokens); @include token-utils.create-token-values(tokens-mat-checkbox.$prefix, $mat-checkbox-tokens); } diff --git a/src/material/checkbox/checkbox.scss b/src/material/checkbox/checkbox.scss index eba4223a959f..0ff723c563b8 100644 --- a/src/material/checkbox/checkbox.scss +++ b/src/material/checkbox/checkbox.scss @@ -1,174 +1,11 @@ -@use 'sass:map'; @use '@angular/cdk'; -@use '@material/checkbox/checkbox' as mdc-checkbox; -@use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme; -@use '@material/touch-target' as mdc-touch-target; -@use '@material/theme/custom-properties' as mdc-custom-properties; -@use '../core/mdc-helpers/mdc-helpers'; @use '../core/style/layout-common'; @use '../core/style/vendor-prefixes'; -@use '../core/tokens/m2/mdc/checkbox' as tokens-mdc-checkbox; @use '../core/tokens/m2/mat/checkbox' as tokens-mat-checkbox; @use '../core/tokens/token-utils'; +@use './checkbox-common'; -@include mdc-custom-properties.configure($emit-fallback-values: false, $emit-fallback-vars: false) { - // Add the checkbox static styles. - @include mdc-checkbox.static-styles(); - - $mdc-checkbox-slots: tokens-mdc-checkbox.get-token-slots(); - - .mdc-checkbox { - // Add the slots for MDC checkbox. - @include mdc-checkbox-theme.theme-styles( - map.merge( - $mdc-checkbox-slots, - ( - // Angular Material focuses the native input. rather than the element MDC expects, - // so we create this slot ourselves. - selected-focus-icon-color: null, - unselected-focus-icon-color: null, - // MDC expects `.mdc-checkbox__ripple::before` to be the state layer, but we use - // `.mdc-checkbox__ripple` instead, so we emit the state layer slots ourselves. - unselected-hover-state-layer-opacity: null, - unselected-hover-state-layer-color: null, - unselected-focus-state-layer-opacity: null, - unselected-focus-state-layer-color: null, - unselected-pressed-state-layer-opacity: null, - unselected-pressed-state-layer-color: null, - selected-hover-state-layer-opacity: null, - selected-hover-state-layer-color: null, - selected-focus-state-layer-opacity: null, - selected-focus-state-layer-color: null, - selected-pressed-state-layer-opacity: null, - selected-pressed-state-layer-color: null - ) - ) - ); - - @include token-utils.use-tokens(tokens-mdc-checkbox.$prefix, $mdc-checkbox-slots) { - // MDC expects focus on .mdc-checkbox, but we focus the native element instead, so we need to - // emit a our own slot for the focus styles. - .mdc-checkbox__native-control:enabled:focus { - // Extra `:focus` included to achieve higher specificity than MDC's `:hover` style. - &:focus:not(:checked):not(:indeterminate) ~ .mdc-checkbox__background { - @include token-utils.create-token-slot(border-color, unselected-focus-icon-color); - } - - &:checked, - &:indeterminate { - & ~ .mdc-checkbox__background { - @include token-utils.create-token-slot(border-color, selected-focus-icon-color); - @include token-utils.create-token-slot(background-color, selected-focus-icon-color); - } - } - } - - // MDC expects `.mdc-checkbox__ripple::before` to be the state layer, but we use - // `.mdc-checkbox__ripple` instead, so we emit the state layer slots ourselves. - &:hover { - .mdc-checkbox__ripple { - @include token-utils.create-token-slot(opacity, unselected-hover-state-layer-opacity); - @include token-utils.create-token-slot( - background-color, - unselected-hover-state-layer-color - ); - } - - .mat-mdc-checkbox-ripple .mat-ripple-element { - @include token-utils.create-token-slot( - background-color, - unselected-hover-state-layer-color - ); - } - } - - .mdc-checkbox__native-control:focus { - & ~ .mdc-checkbox__ripple { - @include token-utils.create-token-slot(opacity, unselected-focus-state-layer-opacity); - @include token-utils.create-token-slot( - background-color, - unselected-focus-state-layer-color - ); - } - - & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { - @include token-utils.create-token-slot( - background-color, - unselected-focus-state-layer-color - ); - } - } - - &:active .mdc-checkbox__native-control { - & ~ .mdc-checkbox__ripple { - @include token-utils.create-token-slot(opacity, unselected-pressed-state-layer-opacity); - @include token-utils.create-token-slot( - background-color, - unselected-pressed-state-layer-color - ); - } - - & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { - @include token-utils.create-token-slot( - background-color, - unselected-pressed-state-layer-color - ); - } - } - - &:hover .mdc-checkbox__native-control:checked { - & ~ .mdc-checkbox__ripple { - @include token-utils.create-token-slot(opacity, selected-hover-state-layer-opacity); - @include token-utils.create-token-slot( - background-color, - selected-hover-state-layer-color - ); - } - - & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { - @include token-utils.create-token-slot( - background-color, - selected-hover-state-layer-color - ); - } - } - - .mdc-checkbox__native-control:focus:checked { - & ~ .mdc-checkbox__ripple { - @include token-utils.create-token-slot(opacity, selected-focus-state-layer-opacity); - @include token-utils.create-token-slot( - background-color, - selected-focus-state-layer-color - ); - } - - & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { - @include token-utils.create-token-slot( - background-color, - selected-focus-state-layer-color - ); - } - } - - &:active .mdc-checkbox__native-control:checked { - & ~ .mdc-checkbox__ripple { - @include token-utils.create-token-slot(opacity, selected-pressed-state-layer-opacity); - @include token-utils.create-token-slot( - background-color, - selected-pressed-state-layer-color - ); - } - - & ~ .mat-mdc-checkbox-ripple .mat-ripple-element { - @include token-utils.create-token-slot( - background-color, - selected-pressed-state-layer-color - ); - } - } - } - } -} +@include checkbox-common.checkbox-structure(true); .mat-mdc-checkbox { // The host node defaults to `display: inline`, we have to change it in order for margins to work. @@ -183,15 +20,6 @@ @include vendor-prefixes.color-adjust(exact); } - // Angular Material supports disabling all animations when NoopAnimationsModule is imported. - &._mat-animation-noopable { - *, - *::before { - transition: none !important; - animation: none !important; - } - } - // Clicking the label toggles the checkbox, but MDC does not include any styles that inform the // user of this. Therefore we add the pointer cursor on top of MDC's styles. label { @@ -269,10 +97,12 @@ // Element used to provide a larger tap target for users on touch devices. .mat-mdc-checkbox-touch-target { - @include mdc-touch-target.touch-target( - $set-width: true, - $query: mdc-helpers.$mdc-base-styles-query - ); + position: absolute; + top: 50%; + left: 50%; + height: 48px; + width: 48px; + transform: translate(-50%, -50%); @include token-utils.use-tokens( tokens-mat-checkbox.$prefix, diff --git a/src/material/core/tokens/m2/mdc/_checkbox.scss b/src/material/core/tokens/m2/mdc/_checkbox.scss index b461fea1605b..5a230ebe7c1f 100644 --- a/src/material/core/tokens/m2/mdc/_checkbox.scss +++ b/src/material/core/tokens/m2/mdc/_checkbox.scss @@ -35,6 +35,9 @@ $prefix: (mdc, checkbox); // ============================================================================================= // = TOKENS NOT USED IN ANGULAR MATERIAL = // ============================================================================================= + selected-pressed-icon-color: null, + unselected-pressed-icon-color: null, + // MDC currently doesn't output a slot for these tokens. disabled-selected-icon-opacity: null, disabled-unselected-icon-opacity: null, @@ -79,16 +82,12 @@ $prefix: (mdc, checkbox); selected-hover-icon-color: $palette-selected, // The color of the checkbox fill when the checkbox is selected. selected-icon-color: $palette-selected, - // The color of the checkbox fill when the checkbox is selected an pressed. - selected-pressed-icon-color: $palette-selected, // The color of the checkbox border when the checkbox is unselected and focused. unselected-focus-icon-color: $active-border-color, // The color of the checkbox border when the checkbox is unselected and hovered. unselected-hover-icon-color: $active-border-color, // The color of the checkbox border when the checkbox is unselected. unselected-icon-color: $border-color, - // The color of the checkbox border when the checkbox is unselected and pressed. - unselected-pressed-icon-color: $border-color, // The color of the ripple when the checkbox is selected and focused. selected-focus-state-layer-color: $palette-default, // The color of the ripple when the checkbox is selected and hovered. diff --git a/src/material/list/BUILD.bazel b/src/material/list/BUILD.bazel index 950518a63151..5bd7a26b1467 100644 --- a/src/material/list/BUILD.bazel +++ b/src/material/list/BUILD.bazel @@ -71,6 +71,7 @@ sass_binary( ":list_scss_lib", "//:mdc_sass_lib", "//src/cdk:sass_lib", + "//src/material/checkbox:checkbox_scss_lib", "//src/material/core:core_scss_lib", ], ) diff --git a/src/material/list/_list-item-hcm-indicator.scss b/src/material/list/_list-item-hcm-indicator.scss index cc88f0539693..488064bb58a2 100644 --- a/src/material/list/_list-item-hcm-indicator.scss +++ b/src/material/list/_list-item-hcm-indicator.scss @@ -6,25 +6,25 @@ // its background color. Since that doesn't work in HCM, this mixin provides an alternative by // rendering a circle. @mixin private-high-contrast-list-item-indicator() { - @include cdk.high-contrast(active, off) { - &::after { - $size: 10px; - content: ''; - position: absolute; - top: 50%; - right: mdc-list-variables.$side-padding; - transform: translateY(-50%); - width: $size; - height: 0; - border-bottom: solid $size; - border-radius: $size; - } + @include cdk.high-contrast(active, off) { + &::after { + $size: 10px; + content: ''; + position: absolute; + top: 50%; + right: mdc-list-variables.$side-padding; + transform: translateY(-50%); + width: $size; + height: 0; + border-bottom: solid $size; + border-radius: $size; + } - [dir='rtl'] { - &::after { - right: auto; - left: mdc-list-variables.$side-padding; - } - } + [dir='rtl'] { + &::after { + right: auto; + left: mdc-list-variables.$side-padding; + } } + } } diff --git a/src/material/list/_list-theme.scss b/src/material/list/_list-theme.scss index b88620f0743e..cbd129154e94 100644 --- a/src/material/list/_list-theme.scss +++ b/src/material/list/_list-theme.scss @@ -1,6 +1,5 @@ @use 'sass:map'; @use '@material/list/evolution-mixins'; -@use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme; @use '@material/radio/radio-theme' as mdc-radio-theme; @use '@material/list/list-theme' as mdc-list-theme; @@ -63,13 +62,16 @@ } .mat-mdc-list-option { - @include mdc-checkbox-theme.theme(tokens-mdc-checkbox.get-color-tokens($theme, primary)); + @include token-utils.create-token-values( + tokens-mdc-checkbox.$prefix, tokens-mdc-checkbox.get-color-tokens($theme, primary)); } .mat-mdc-list-option.mat-accent { - @include mdc-checkbox-theme.theme(tokens-mdc-checkbox.get-color-tokens($theme, accent)); + @include token-utils.create-token-values( + tokens-mdc-checkbox.$prefix, tokens-mdc-checkbox.get-color-tokens($theme, accent)); } .mat-mdc-list-option.mat-warn { - @include mdc-checkbox-theme.theme(tokens-mdc-checkbox.get-color-tokens($theme, warn)); + @include token-utils.create-token-values( + tokens-mdc-checkbox.$prefix, tokens-mdc-checkbox.get-color-tokens($theme, warn)); } // There is no token for activated color on nav list. diff --git a/src/material/list/list-option.scss b/src/material/list/list-option.scss index 90c1eb876f9d..9818bd68d278 100644 --- a/src/material/list/list-option.scss +++ b/src/material/list/list-option.scss @@ -1,10 +1,8 @@ -@use '@material/checkbox/checkbox' as mdc-checkbox; -@use '@material/checkbox/checkbox-theme' as mdc-checkbox-theme; @use '@material/radio/radio' as mdc-radio; @use '@material/radio/radio-theme' as mdc-radio-theme; +@use '../checkbox/checkbox-common'; @use '../core/mdc-helpers/mdc-helpers'; -@use '../core/tokens/m2/mdc/checkbox' as tokens-mdc-checkbox; @use '../core/tokens/m2/mdc/radio' as tokens-mdc-radio; @use './list-option-trailing-avatar-compat'; @use './list-item-hcm-indicator'; @@ -17,24 +15,17 @@ // The MDC-based list-option uses the MDC checkbox/radio for the selection indicators. // We need to ensure that the checkbox and radio styles are not included for the list-option. @include mdc-helpers.disable-mdc-fallback-declarations { - @include mdc-checkbox.static-styles( - $query: mdc-helpers.$mdc-base-styles-without-animation-query); @include mdc-radio.static-styles( $query: mdc-helpers.$mdc-base-styles-without-animation-query); &:not(._mat-animation-noopable) { - @include mdc-checkbox.static-styles($query: animation); @include mdc-radio.static-styles($query: animation); } } // We can't use the MDC checkbox here directly, because this checkbox is purely // decorative and including the MDC one will bring in unnecessary JS. - .mdc-checkbox { - // MDC theme styles also include structural styles so we have to include the theme at least - // once here. The values will be overwritten by our own theme file afterwards. - @include mdc-checkbox-theme.theme-styles(tokens-mdc-checkbox.get-token-slots()); - } + @include checkbox-common.checkbox-structure(false); // We can't use the MDC radio here directly, because this radio is purely // decorative and including the MDC one will bring in unnecessary JS.