diff --git a/radio/internal/_radio.scss b/radio/internal/_radio.scss
index ada6deea9c..ab686554c1 100644
--- a/radio/internal/_radio.scss
+++ b/radio/internal/_radio.scss
@@ -33,168 +33,153 @@ $_md-sys-motion: tokens.md-sys-motion-values();
@mixin styles() {
$tokens: tokens.md-comp-radio-values();
- @layer {
- :host {
- @each $token, $value in $tokens {
- --_#{$token}: var(--md-radio-#{$token}, #{$value});
- }
-
- @include ripple.theme(
- (
- hover-color: var(--_hover-state-layer-color),
- hover-opacity: var(--_hover-state-layer-opacity),
- pressed-color: var(--_pressed-state-layer-color),
- pressed-opacity: var(--_pressed-state-layer-opacity),
- )
- );
-
- display: inline-flex;
- height: var(--_icon-size);
- outline: none;
- position: relative;
- vertical-align: top; // Fix extra space when placed inside display: block
- width: var(--_icon-size);
- // Remove highlight color for mobile Safari
- -webkit-tap-highlight-color: transparent;
- }
-
- :host([touch-target='wrapper']) {
- margin: max(0px, ((48px - var(--_icon-size)) / 2));
- }
+ :host {
+ @each $token, $value in $tokens {
+ --_#{$token}: var(--md-radio-#{$token}, #{$value});
+ }
+
+ @include ripple.theme(
+ (
+ hover-color: var(--_hover-state-layer-color),
+ hover-opacity: var(--_hover-state-layer-opacity),
+ pressed-color: var(--_pressed-state-layer-color),
+ pressed-opacity: var(--_pressed-state-layer-opacity),
+ )
+ );
+
+ display: inline-flex;
+ height: var(--_icon-size);
+ outline: none;
+ position: relative;
+ vertical-align: top; // Fix extra space when placed inside display: block
+ width: var(--_icon-size);
+ // Remove highlight color for mobile Safari
+ -webkit-tap-highlight-color: transparent;
+ }
- .container {
- display: flex;
- height: 100%;
- place-content: center;
- place-items: center;
- width: 100%;
- }
+ :host([touch-target='wrapper']) {
+ margin: max(0px, ((48px - var(--_icon-size)) / 2));
+ }
- md-focus-ring {
- height: 44px;
- inset: unset;
- width: 44px;
- }
+ .container {
+ display: flex;
+ height: 100%;
+ place-content: center;
+ place-items: center;
+ width: 100%;
+ }
- .checked {
- @include ripple.theme(
- (
- hover-color: var(--_selected-hover-state-layer-color),
- hover-opacity: var(--_selected-hover-state-layer-opacity),
- pressed-color: var(--_selected-pressed-state-layer-color),
- pressed-opacity: var(--_selected-pressed-state-layer-opacity),
- )
- );
- }
+ md-focus-ring {
+ height: 44px;
+ inset: unset;
+ width: 44px;
+ }
- // is also the touch target
- input {
- appearance: none;
- height: 48px;
- margin: 0;
- position: absolute;
- width: 48px;
- }
+ .checked {
+ @include ripple.theme(
+ (
+ hover-color: var(--_selected-hover-state-layer-color),
+ hover-opacity: var(--_selected-hover-state-layer-opacity),
+ pressed-color: var(--_selected-pressed-state-layer-color),
+ pressed-opacity: var(--_selected-pressed-state-layer-opacity),
+ )
+ );
+ }
- :host([touch-target='none']) input {
- width: 100%;
- height: 100%;
- }
+ // is also the touch target
+ input {
+ appearance: none;
+ height: 48px;
+ margin: 0;
+ position: absolute;
+ width: 48px;
+ }
- md-ripple {
- border-radius: 50%;
- height: var(--_state-layer-size);
- inset: unset;
- width: var(--_state-layer-size);
- }
+ :host([touch-target='none']) input {
+ width: 100%;
+ height: 100%;
+ }
- .icon {
- fill: var(--_icon-color);
- inset: 0;
- position: absolute;
- }
+ md-ripple {
+ border-radius: 50%;
+ height: var(--_state-layer-size);
+ inset: unset;
+ width: var(--_state-layer-size);
+ }
- .outer.circle {
- // Outline color enter/exit transition
- transition: fill 50ms linear;
- }
+ .icon {
+ fill: var(--_icon-color);
+ inset: 0;
+ position: absolute;
+ }
- .inner.circle {
- opacity: 0;
- transform-origin: center;
- transition: opacity 50ms linear;
- }
+ .outer.circle {
+ // Outline color enter/exit transition
+ transition: fill 50ms linear;
+ }
- .checked .icon {
- fill: var(--_selected-icon-color);
- }
+ .inner.circle {
+ opacity: 0;
+ transform-origin: center;
+ transition: opacity 50ms linear;
+ }
- .checked .inner.circle {
- animation: inner-circle-grow 300ms
- map.get($_md-sys-motion, easing-emphasized-decelerate);
- opacity: 1;
- }
+ .checked .icon {
+ fill: var(--_selected-icon-color);
+ }
- @keyframes inner-circle-grow {
- from {
- transform: scale(0);
- }
- to {
- transform: scale(1);
- }
- }
+ .checked .inner.circle {
+ animation: inner-circle-grow 300ms
+ map.get($_md-sys-motion, easing-emphasized-decelerate);
+ opacity: 1;
+ }
- // Don't animate when disabled
- :host([disabled]) .circle {
- animation-duration: 0s;
- transition-duration: 0s;
+ @keyframes inner-circle-grow {
+ from {
+ transform: scale(0);
}
-
- :host(:hover) .icon {
- fill: var(--_hover-icon-color);
+ to {
+ transform: scale(1);
}
+ }
- :host(:focus-within) .icon {
- fill: var(--_focus-icon-color);
- }
+ // Don't animate when disabled
+ :host([disabled]) .circle {
+ animation-duration: 0s;
+ transition-duration: 0s;
+ }
- :host(:active) .icon {
- fill: var(--_pressed-icon-color);
- }
+ :host(:hover) .icon {
+ fill: var(--_hover-icon-color);
+ }
- :host([disabled]) .icon {
- fill: var(--_disabled-unselected-icon-color);
- opacity: var(--_disabled-unselected-icon-opacity);
- }
+ :host(:focus-within) .icon {
+ fill: var(--_focus-icon-color);
+ }
- :host(:hover) .checked .icon {
- fill: var(--_selected-hover-icon-color);
- }
+ :host(:active) .icon {
+ fill: var(--_pressed-icon-color);
+ }
- :host(:focus-within) .checked .icon {
- fill: var(--_selected-focus-icon-color);
- }
+ :host([disabled]) .icon {
+ fill: var(--_disabled-unselected-icon-color);
+ opacity: var(--_disabled-unselected-icon-opacity);
+ }
- :host(:active) .checked .icon {
- fill: var(--_selected-pressed-icon-color);
- }
+ :host(:hover) .checked .icon {
+ fill: var(--_selected-hover-icon-color);
+ }
- :host([disabled]) .checked .icon {
- fill: var(--_disabled-selected-icon-color);
- opacity: var(--_disabled-selected-icon-opacity);
- }
+ :host(:focus-within) .checked .icon {
+ fill: var(--_selected-focus-icon-color);
}
- @layer hcm {
- @media (forced-colors: active) {
- .icon {
- fill: CanvasText;
- }
+ :host(:active) .checked .icon {
+ fill: var(--_selected-pressed-icon-color);
+ }
- :host([disabled]) .icon {
- fill: GrayText;
- opacity: 1;
- }
- }
+ :host([disabled]) .checked .icon {
+ fill: var(--_disabled-selected-icon-color);
+ opacity: var(--_disabled-selected-icon-opacity);
}
}
diff --git a/radio/internal/forced-colors-styles.scss b/radio/internal/forced-colors-styles.scss
new file mode 100644
index 0000000000..e316655942
--- /dev/null
+++ b/radio/internal/forced-colors-styles.scss
@@ -0,0 +1,29 @@
+//
+// Copyright 2023 Google LLC
+// SPDX-License-Identifier: Apache-2.0
+//
+
+// go/keep-sorted start
+@use './radio';
+// go/keep-sorted end
+
+@media (forced-colors: active) {
+ :host {
+ @include radio.theme(
+ (
+ disabled-selected-icon-color: GrayText,
+ disabled-selected-icon-opacity: 1,
+ disabled-unselected-icon-color: GrayText,
+ disabled-unselected-icon-opacity: 1,
+ selected-icon-color: CanvasText,
+ selected-hover-icon-color: CanvasText,
+ selected-focus-icon-color: CanvasText,
+ selected-pressed-icon-color: CanvasText,
+ icon-color: CanvasText,
+ hover-icon-color: CanvasText,
+ focus-icon-color: CanvasText,
+ pressed-icon-color: CanvasText,
+ )
+ );
+ }
+}
diff --git a/radio/radio.ts b/radio/radio.ts
index 4971ef51e5..1eabfd3c65 100644
--- a/radio/radio.ts
+++ b/radio/radio.ts
@@ -6,6 +6,7 @@
import {customElement} from 'lit/decorators.js';
+import {styles as forcedColorsStyles} from './internal/forced-colors-styles.css.js';
import {Radio} from './internal/radio.js';
import {styles} from './internal/radio-styles.css.js';
@@ -33,5 +34,5 @@ declare global {
*/
@customElement('md-radio')
export class MdRadio extends Radio {
- static override styles = [styles];
+ static override styles = [styles, forcedColorsStyles];
}
diff --git a/testing/transform-pseudo-classes.ts b/testing/transform-pseudo-classes.ts
index bc17977d6f..1f2374dbda 100644
--- a/testing/transform-pseudo-classes.ts
+++ b/testing/transform-pseudo-classes.ts
@@ -96,7 +96,7 @@ export function transformPseudoClasses(
function visitRule(
rule: CSSRule, stylesheet: CSSStyleSheet|CSSGroupingRule, index: number,
pseudoClasses: string[]) {
- if (rule instanceof CSSGroupingRule) {
+ if (rule instanceof CSSMediaRule || rule instanceof CSSSupportsRule) {
for (let i = rule.cssRules.length - 1; i >= 0; i--) {
visitRule(rule.cssRules[i], rule, i, pseudoClasses);
}