diff --git a/src/dev-app/list/list-demo.html b/src/dev-app/list/list-demo.html
index 13ec4aec9b94..fbb560fdf191 100644
--- a/src/dev-app/list/list-demo.html
+++ b/src/dev-app/list/list-demo.html
@@ -126,21 +126,21 @@
Selection list
color="primary">
Groceries
- Bananas
- Oranges
- Apples
- Strawberries
+ Bananas
+ Oranges
+ Apples
+ Strawberries
Dogs
-
+
Shiba Inu
-
+
Other Shiba Inu
@@ -177,9 +177,9 @@ Single Selection list
Favorite Grocery
Bananas
- Oranges
- Apples
- Strawberries
+ Oranges
+ Apples
+ Strawberries
Selected: {{favoriteOptions | json}}
@@ -239,19 +239,19 @@ Line alignment
Icon alignment in selection list
-
+
info
Bananas
-
+
info
Oranges
-
+
info
Cake
-
+
info
Fries
diff --git a/src/dev-app/list/list-demo.ts b/src/dev-app/list/list-demo.ts
index 9ddc9ed36c71..bad097b791fa 100644
--- a/src/dev-app/list/list-demo.ts
+++ b/src/dev-app/list/list-demo.ts
@@ -9,7 +9,7 @@
import {Component} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MatButtonModule} from '@angular/material/button';
-import {MatListModule, MatListOptionCheckboxPosition} from '@angular/material/list';
+import {MatListModule, MatListOptionTogglePosition} from '@angular/material/list';
import {MatIconModule} from '@angular/material/icon';
import {CommonModule} from '@angular/common';
@@ -23,7 +23,7 @@ import {CommonModule} from '@angular/common';
export class ListDemo {
items: string[] = ['Pepper', 'Salt', 'Paprika'];
- checkboxPosition: MatListOptionCheckboxPosition = 'before';
+ togglePosition: MatListOptionTogglePosition = 'before';
contacts: {name: string; headline: string}[] = [
{name: 'Nancy', headline: 'Software engineer'},
@@ -75,7 +75,7 @@ export class ListDemo {
}
toggleCheckboxPosition() {
- this.checkboxPosition = this.checkboxPosition === 'before' ? 'after' : 'before';
+ this.togglePosition = this.togglePosition === 'before' ? 'after' : 'before';
}
favoriteOptions: string[] = [];
diff --git a/src/material/legacy-list/selection-list.ts b/src/material/legacy-list/selection-list.ts
index 9afffc43ab88..b8736775da63 100644
--- a/src/material/legacy-list/selection-list.ts
+++ b/src/material/legacy-list/selection-list.ts
@@ -74,7 +74,7 @@ export class MatLegacySelectionListChange {
/**
* Type describing possible positions of a checkbox in a list option
* with respect to the list item's text.
- * @deprecated Use `MatListOptionCheckboxPosition` from `@angular/material/list` instead. See https://material.angular.io/guide/mdc-migration for information about migrating.
+ * @deprecated Use `MatListOptionTogglePosition` from `@angular/material/list` instead. See https://material.angular.io/guide/mdc-migration for information about migrating.
* @breaking-change 17.0.0
*/
export type MatLegacyListOptionCheckboxPosition = 'before' | 'after';
diff --git a/src/material/list/BUILD.bazel b/src/material/list/BUILD.bazel
index 8cca815c05fb..c0bf202baa63 100644
--- a/src/material/list/BUILD.bazel
+++ b/src/material/list/BUILD.bazel
@@ -52,6 +52,7 @@ sass_library(
"//:mdc_sass_lib",
"//src/material/checkbox:checkbox_scss_lib",
"//src/material/core:core_scss_lib",
+ "//src/material/radio:radio_scss_lib",
],
)
diff --git a/src/material/list/_list-option-theme.scss b/src/material/list/_list-option-theme.scss
index 021053ee259b..1569e9865dde 100644
--- a/src/material/list/_list-option-theme.scss
+++ b/src/material/list/_list-option-theme.scss
@@ -2,13 +2,16 @@
@use '../core/mdc-helpers/mdc-helpers';
@use '../checkbox/checkbox-private';
@use './list-option-trailing-avatar-compat';
+@use '../radio/radio-private';
-// Mixin that overrides the selected item and checkbox colors for list options. By
-// default, the MDC list uses the `primary` color for list items. The MDC checkbox
-// inside list options by default uses the `primary` color too.
+// Mixin that overrides the selected item and toggle indicator colors for list
+// options. By default, the MDC list uses the `primary` color for list items.
+// The MDC radio/checkbox inside list options by default uses the `primary`
+// color too.
@mixin private-list-option-color-override($color-config, $color, $mdc-color) {
& .mdc-list-item__start, & .mdc-list-item__end {
@include checkbox-private.private-checkbox-styles-with-color($color-config, $color, $mdc-color);
+ @include radio-private.private-radio-color($color-config, $color);
}
}
diff --git a/src/material/list/list-item-sections.ts b/src/material/list/list-item-sections.ts
index 78101de89688..6a212923b06c 100644
--- a/src/material/list/list-item-sections.ts
+++ b/src/material/list/list-item-sections.ts
@@ -52,17 +52,17 @@ export class MatListItemMeta {}
/**
* @docs-private
*
- * MDC uses the very intuitively named classes `.mdc-list-item__start` and `.mat-list-item__end`
- * to position content such as icons or checkboxes that comes either before or after the text
- * content respectively. This directive detects the placement of the checkbox and applies the
+ * MDC uses the very intuitively named classes `.mdc-list-item__start` and `.mat-list-item__end` to
+ * position content such as icons or checkboxes/radios that comes either before or after the text
+ * content respectively. This directive detects the placement of the checkbox/radio and applies the
* correct MDC class to position the icon/avatar on the opposite side.
*/
@Directive({
host: {
- // MDC uses intuitively named classes `.mdc-list-item__start` and `.mat-list-item__end`
- // to position content such as icons or checkboxes that comes either before or after the text
- // content respectively. This directive detects the placement of the checkbox and applies the
- // correct MDC class to position the icon/avatar on the opposite side.
+ // MDC uses intuitively named classes `.mdc-list-item__start` and `.mat-list-item__end` to
+ // position content such as icons or checkboxes/radios that comes either before or after the
+ // text content respectively. This directive detects the placement of the checkbox/radio and
+ // applies the correct MDC class to position the icon/avatar on the opposite side.
'[class.mdc-list-item__start]': '_isAlignedAtStart()',
'[class.mdc-list-item__end]': '!_isAlignedAtStart()',
},
@@ -72,8 +72,8 @@ export class _MatListItemGraphicBase {
_isAlignedAtStart() {
// By default, in all list items the graphic is aligned at start. In list options,
- // the graphic is only aligned at start if the checkbox is at the end.
- return !this._listOption || this._listOption?._getCheckboxPosition() === 'after';
+ // the graphic is only aligned at start if the checkbox/radio is at the end.
+ return !this._listOption || this._listOption?._getTogglePosition() === 'after';
}
}
diff --git a/src/material/list/list-option-types.ts b/src/material/list/list-option-types.ts
index fe6557ea6f1e..c65118ba3223 100644
--- a/src/material/list/list-option-types.ts
+++ b/src/material/list/list-option-types.ts
@@ -9,10 +9,10 @@
import {InjectionToken} from '@angular/core';
/**
- * Type describing possible positions of a checkbox in a list option
+ * Type describing possible positions of a checkbox or radio in a list option
* with respect to the list item's text.
*/
-export type MatListOptionCheckboxPosition = 'before' | 'after';
+export type MatListOptionTogglePosition = 'before' | 'after';
/**
* Interface describing a list option. This is used to avoid circular
@@ -20,7 +20,7 @@ export type MatListOptionCheckboxPosition = 'before' | 'after';
* @docs-private
*/
export interface ListOption {
- _getCheckboxPosition(): MatListOptionCheckboxPosition;
+ _getTogglePosition(): MatListOptionTogglePosition;
}
/**
diff --git a/src/material/list/list-option.html b/src/material/list/list-option.html
index 3dd89050aa65..5d11eb2a5d0e 100644
--- a/src/material/list/list-option.html
+++ b/src/material/list/list-option.html
@@ -1,5 +1,5 @@
@@ -25,11 +25,27 @@
+
+
+
+
+
+
+
+
@@ -49,6 +65,10 @@
+
+
+
+
diff --git a/src/material/list/list-option.scss b/src/material/list/list-option.scss
index ea5e002a90af..8e06be1352ad 100644
--- a/src/material/list/list-option.scss
+++ b/src/material/list/list-option.scss
@@ -1,9 +1,12 @@
@use 'sass:map';
@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 '../core/mdc-helpers/mdc-helpers';
@use '../checkbox/checkbox-private';
+@use '../radio/radio-private';
@use './list-option-trailing-avatar-compat';
@use './list-item-hcm-indicator';
@@ -12,42 +15,58 @@
@include list-option-trailing-avatar-compat.core-styles($query: mdc-helpers.$mdc-base-styles-query);
.mat-mdc-list-option {
- // The MDC-based list-option uses the MDC checkbox for the selection indicators.
- // We need to ensure that the checkbox styles are not included for the list-option.
+ // 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 {
- $config: map.merge(checkbox-private.$private-checkbox-theme-config, (
- // Since this checkbox isn't interactive, we can exclude the focus/hover/press styles.
+ $without-ripple-config: (
+ // Since this checkbox/radio isn't interactive, we can exclude the focus/hover/press styles.
selected-focus-icon-color: null,
selected-hover-icon-color: null,
selected-pressed-icon-color: null,
unselected-focus-icon-color: null,
unselected-hover-icon-color: null,
unselected-pressed-icon-color: null,
- ));
+ );
+
+ // 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 {
+ $config: map.merge(checkbox-private.$private-checkbox-theme-config, $without-ripple-config);
// 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($config);
}
- // The internal checkbox is purely decorative, but because it's an `input`, the user can still
- // focus it by tabbing or clicking. Furthermore, `mat-list-option` has the `option` role which
- // doesn't allow a nested `input`. We use `display: none` both to remove it from the tab order
- // and to prevent focus from reaching it through the screen reader's forms mode. Ideally we'd
- // remove the `input` completely, but we can't because MDC uses a `:checked` selector to
+ // 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.
+ .mdc-radio {
+ $config: map.merge(radio-private.$private-radio-theme-config, $without-ripple-config);
+
+ // 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-radio-theme.theme-styles($config);
+ }
+
+
+ // The internal checkbox/radio is purely decorative, but because it's an `input`, the user can
+ // still focus it by tabbing or clicking. Furthermore, `mat-list-option` has the `option` role
+ // which doesn't allow a nested `input`. We use `display: none` both to remove it from the tab
+ // order and to prevent focus from reaching it through the screen reader's forms mode. Ideally
+ // we'd remove the `input` completely, but we can't because MDC uses a `:checked` selector to
// toggle the selected styles.
- .mdc-checkbox__native-control {
+ .mdc-checkbox__native-control, .mdc-radio__native-control {
display: none;
}
}
diff --git a/src/material/list/list-option.ts b/src/material/list/list-option.ts
index 87f21b4fdb69..c7795e0cf62a 100644
--- a/src/material/list/list-option.ts
+++ b/src/material/list/list-option.ts
@@ -30,7 +30,7 @@ import {
} from '@angular/core';
import {MAT_RIPPLE_GLOBAL_OPTIONS, RippleGlobalOptions, ThemePalette} from '@angular/material/core';
import {MatListBase, MatListItemBase} from './list-base';
-import {LIST_OPTION, ListOption, MatListOptionCheckboxPosition} from './list-option-types';
+import {LIST_OPTION, ListOption, MatListOptionTogglePosition} from './list-option-types';
import {MatListItemLine, MatListItemTitle} from './list-item-sections';
import {Platform} from '@angular/cdk/platform';
@@ -67,16 +67,18 @@ export interface SelectionList extends MatListBase {
// As per MDC, only list items in single selection mode should receive the `--selected`
// class. For multi selection, the checkbox is used as indicator.
'[class.mdc-list-item--selected]': 'selected && !_selectionList.multiple',
- // Based on the checkbox position and whether there are icons or avatars, we apply MDC's
+ // Based on the checkbox/radio position and whether there are icons or avatars, we apply MDC's
// list-item `--leading` and `--trailing` classes.
'[class.mdc-list-item--with-leading-avatar]': '_hasProjected("avatars", "before")',
'[class.mdc-list-item--with-leading-icon]': '_hasProjected("icons", "before")',
'[class.mdc-list-item--with-trailing-icon]': '_hasProjected("icons", "after")',
'[class.mat-mdc-list-option-with-trailing-avatar]': '_hasProjected("avatars", "after")',
- // Based on the checkbox position, we apply the `--leading` or `--trailing` MDC classes
- // which ensure that the checkbox is positioned correctly within the list item.
+ // Based on the checkbox/radio position, we apply the `--leading` or `--trailing` MDC classes
+ // which ensure that the checkbox/radio is positioned correctly within the list item.
'[class.mdc-list-item--with-leading-checkbox]': '_hasCheckboxAt("before")',
'[class.mdc-list-item--with-trailing-checkbox]': '_hasCheckboxAt("after")',
+ '[class.mdc-list-item--with-leading-radio]': '_hasRadioAt("before")',
+ '[class.mdc-list-item--with-trailing-radio]': '_hasRadioAt("after")',
'[class.mat-accent]': 'color !== "primary" && color !== "warn"',
'[class.mat-warn]': 'color === "warn"',
'[class._mat-animation-noopable]': '_noopAnimations',
@@ -105,10 +107,23 @@ export class MatListOption extends MatListItemBase implements ListOption, OnInit
@Output()
readonly selectedChange: EventEmitter = new EventEmitter();
- /** Whether the label should appear before or after the checkbox. Defaults to 'after' */
- @Input() checkboxPosition: MatListOptionCheckboxPosition = 'after';
+ /** Whether the label should appear before or after the checkbox/radio. Defaults to 'after' */
+ @Input() togglePosition: MatListOptionTogglePosition = 'after';
- /** Theme color of the list option. This sets the color of the checkbox. */
+ /**
+ * Whether the label should appear before or after the checkbox/radio. Defaults to 'after'
+ *
+ * @deprecated Use `togglePosition` instead.
+ * @breaking-change 17.0.0
+ */
+ @Input() get checkboxPosition(): MatListOptionTogglePosition {
+ return this.togglePosition;
+ }
+ set checkboxPosition(value: MatListOptionTogglePosition) {
+ this.togglePosition = value;
+ }
+
+ /** Theme color of the list option. This sets the color of the checkbox/radio. */
@Input()
get color(): ThemePalette {
return this._color || this._selectionList.color;
@@ -225,8 +240,13 @@ export class MatListOption extends MatListItemBase implements ListOption, OnInit
}
/** Whether a checkbox is shown at the given position. */
- _hasCheckboxAt(position: MatListOptionCheckboxPosition): boolean {
- return this._selectionList.multiple && this._getCheckboxPosition() === position;
+ _hasCheckboxAt(position: MatListOptionTogglePosition): boolean {
+ return this._selectionList.multiple && this._getTogglePosition() === position;
+ }
+
+ /** Where a radio indicator is shown at the given position. */
+ _hasRadioAt(position: MatListOptionTogglePosition): boolean {
+ return !this._selectionList.multiple && this._getTogglePosition() === position;
}
/** Whether icons or avatars are shown at the given position. */
@@ -236,10 +256,10 @@ export class MatListOption extends MatListItemBase implements ListOption, OnInit
/** Gets whether the given type of element is projected at the specified position. */
_hasProjected(type: 'icons' | 'avatars', position: 'before' | 'after'): boolean {
- // If the checkbox is shown at the specified position, neither icons or
+ // If the checkbox/radio is shown at the specified position, neither icons or
// avatars can be shown at the position.
return (
- this._getCheckboxPosition() !== position &&
+ this._getTogglePosition() !== position &&
(type === 'avatars' ? this._avatars.length !== 0 : this._icons.length !== 0)
);
}
@@ -248,9 +268,9 @@ export class MatListOption extends MatListItemBase implements ListOption, OnInit
this._selectionList._onTouched();
}
- /** Gets the current position of the checkbox. */
- _getCheckboxPosition() {
- return this.checkboxPosition || 'after';
+ /** Gets the current position of the checkbox/radio. */
+ _getTogglePosition() {
+ return this.togglePosition || 'after';
}
/**
diff --git a/src/material/list/public-api.ts b/src/material/list/public-api.ts
index 7e8b6b3e6ebe..010eab276ae0 100644
--- a/src/material/list/public-api.ts
+++ b/src/material/list/public-api.ts
@@ -15,5 +15,13 @@ export * from './list-option';
export * from './subheader';
export * from './list-item-sections';
-export {MatListOptionCheckboxPosition} from './list-option-types';
export {MatListOption} from './list-option';
+
+export {
+ MatListOptionTogglePosition,
+ /**
+ * @deprecated Use `MatListOptionTogglePosition` instead.
+ * @breaking-change 17.0.0
+ */
+ MatListOptionTogglePosition as MatListOptionCheckboxPosition,
+} from './list-option-types';
diff --git a/src/material/list/selection-list.spec.ts b/src/material/list/selection-list.spec.ts
index cc9665ac6807..1f94c69fba2e 100644
--- a/src/material/list/selection-list.spec.ts
+++ b/src/material/list/selection-list.spec.ts
@@ -27,7 +27,7 @@ import {By} from '@angular/platform-browser';
import {
MatListModule,
MatListOption,
- MatListOptionCheckboxPosition,
+ MatListOptionTogglePosition,
MatSelectionList,
MatSelectionListChange,
} from './index';
@@ -892,7 +892,7 @@ describe('MDC-based MatSelectionList without forms', () => {
function expectCheckboxAtPosition(
listItemElement: HTMLElement,
- position: MatListOptionCheckboxPosition,
+ position: MatListOptionTogglePosition,
) {
const containerSelector =
position === 'before' ? '.mdc-list-item__start' : 'mdc-list-item__end';
@@ -974,12 +974,12 @@ describe('MDC-based MatSelectionList without forms', () => {
expectCheckboxAtPosition(listOption, 'after');
expectIconAt(listOption, 'before');
- fixture.componentInstance.checkboxPosition = 'before';
+ fixture.componentInstance.togglePosition = 'before';
fixture.detectChanges();
expectCheckboxAtPosition(listOption, 'before');
expectIconAt(listOption, 'after');
- fixture.componentInstance.checkboxPosition = 'after';
+ fixture.componentInstance.togglePosition = 'after';
fixture.detectChanges();
expectCheckboxAtPosition(listOption, 'after');
expectIconAt(listOption, 'before');
@@ -995,12 +995,12 @@ describe('MDC-based MatSelectionList without forms', () => {
expectCheckboxAtPosition(listOption, 'after');
expectAvatarAt(listOption, 'before');
- fixture.componentInstance.checkboxPosition = 'before';
+ fixture.componentInstance.togglePosition = 'before';
fixture.detectChanges();
expectCheckboxAtPosition(listOption, 'before');
expectAvatarAt(listOption, 'after');
- fixture.componentInstance.checkboxPosition = 'after';
+ fixture.componentInstance.togglePosition = 'after';
fixture.detectChanges();
expectCheckboxAtPosition(listOption, 'after');
expectAvatarAt(listOption, 'before');
@@ -1638,21 +1638,21 @@ describe('MDC-based MatSelectionList with forms', () => {
[disableRipple]="listRippleDisabled"
[color]="selectionListColor"
[multiple]="multiple">
-
Inbox (disabled selection-option)
-
Starred
-
+
Sent Mail
-
+
Archive
-
+
Drafts
`,
@@ -1670,16 +1670,16 @@ class SelectionListWithListOptions {
@Component({
template: `
-
+
Inbox (disabled selection-option)
-
+
Starred
-
+
Sent Mail
-
+
Drafts
`,
@@ -1689,16 +1689,16 @@ class SelectionListWithCheckboxPositionAfter {}
@Component({
template: `
-
+
Inbox (disabled selection-option)
-
+
Starred
-
+
Sent Mail
-
+
Drafts
`,
@@ -1742,7 +1742,7 @@ class SelectionListWithSelectedOptionAndValue {
@Component({
template: `
-
+
Inbox
`,
@@ -1838,7 +1838,7 @@ class SelectionListWithCustomComparator {
@Component({
template: `
-
+
I
Inbox
@@ -1846,13 +1846,13 @@ class SelectionListWithCustomComparator {
`,
})
class SelectionListWithAvatar {
- checkboxPosition: MatListOptionCheckboxPosition | undefined;
+ togglePosition: MatListOptionTogglePosition | undefined;
}
@Component({
template: `
-
+
I
Inbox
@@ -1860,7 +1860,7 @@ class SelectionListWithAvatar {
`,
})
class SelectionListWithIcon {
- checkboxPosition: MatListOptionCheckboxPosition | undefined;
+ togglePosition: MatListOptionTogglePosition | undefined;
}
@Component({
diff --git a/src/material/list/testing/list-harness.spec.ts b/src/material/list/testing/list-harness.spec.ts
index e81782563037..4e76b420d6e9 100644
--- a/src/material/list/testing/list-harness.spec.ts
+++ b/src/material/list/testing/list-harness.spec.ts
@@ -639,7 +639,7 @@ class NavListHarnessTest {
@Component({
template: `
-
+
Item
1
icon
diff --git a/src/material/list/testing/selection-list-harness.ts b/src/material/list/testing/selection-list-harness.ts
index c74f2e930394..f770e47514dd 100644
--- a/src/material/list/testing/selection-list-harness.ts
+++ b/src/material/list/testing/selection-list-harness.ts
@@ -7,7 +7,7 @@
*/
import {ComponentHarnessConstructor, HarnessPredicate, parallel} from '@angular/cdk/testing';
-import {MatListOptionCheckboxPosition} from '@angular/material/list';
+import {MatListOptionTogglePosition} from '@angular/material/list';
import {MatListHarnessBase} from './list-harness-base';
import {
ListItemHarnessFilters,
@@ -98,12 +98,18 @@ export class MatListOptionHarness extends MatListItemHarnessBase {
}
private _beforeCheckbox = this.locatorForOptional('.mdc-list-item__start .mdc-checkbox');
+ private _beforeRadio = this.locatorForOptional('.mdc-list-item__start .mdc-radio');
/** Gets the position of the checkbox relative to the list option content. */
- async getCheckboxPosition(): Promise {
+ async getCheckboxPosition(): Promise {
return (await this._beforeCheckbox()) !== null ? 'before' : 'after';
}
+ /** Gets the position of the radio relative to the list option content. */
+ async getRadioPosition(): Promise {
+ return (await this._beforeRadio()) !== null ? 'before' : 'after';
+ }
+
/** Whether the list option is selected. */
async isSelected(): Promise {
return (await (await this.host()).getAttribute('aria-selected')) === 'true';
diff --git a/src/material/radio/BUILD.bazel b/src/material/radio/BUILD.bazel
index 2b899ce5476a..0ce7d6c63c1e 100644
--- a/src/material/radio/BUILD.bazel
+++ b/src/material/radio/BUILD.bazel
@@ -42,6 +42,7 @@ sass_binary(
name = "radio_scss",
src = "radio.scss",
deps = [
+ ":radio_scss_lib",
"//:mdc_sass_lib",
"//src/material/core:core_scss_lib",
],
diff --git a/src/material/radio/_radio-private.scss b/src/material/radio/_radio-private.scss
new file mode 100644
index 000000000000..e38dba1c4a3d
--- /dev/null
+++ b/src/material/radio/_radio-private.scss
@@ -0,0 +1,60 @@
+@use '@material/radio/radio-theme' as mdc-radio-theme;
+@use '@material/theme/theme-color' as mdc-theme-color;
+@use '../core/theming/palette';
+@use '../core/theming/theming';
+@use 'sass:map';
+
+$private-radio-theme-config: map.merge(mdc-radio-theme.$light-theme, (
+ // Exclude the styles we don't need.
+ selected-focus-state-layer-color: null,
+ selected-focus-state-layer-opacity: null,
+ selected-hover-state-layer-color: null,
+ selected-hover-state-layer-opacity: null,
+ selected-pressed-state-layer-color: null,
+ selected-pressed-state-layer-opacity: null,
+ unselected-focus-icon-color: null,
+ unselected-focus-state-layer-color: null,
+ unselected-focus-state-layer-opacity: null,
+ unselected-hover-state-layer-color: null,
+ unselected-hover-state-layer-opacity: null,
+ unselected-pressed-state-layer-color: null,
+ unselected-pressed-state-layer-opacity: null,
+));
+
+@mixin private-radio-color($color-config, $color-palette) {
+ $foreground: map.get($color-config, foreground);
+
+ $on-surface: rgba(mdc-theme-color.$on-surface, 0.54);
+ $is-dark: map.get($color-config, is-dark);
+ $active-border-color: if(
+ $is-dark,
+ theming.get-color-from-palette(palette.$gray-palette, 200),
+ theming.get-color-from-palette(palette.$gray-palette, 900)
+ );
+
+ & {
+ @include mdc-radio-theme.theme((
+ // The disabled colors don't use the `rgba` version, because
+ // MDC applies a separate opacity to disabled buttons.
+ disabled-selected-icon-color: mdc-theme-color.$on-surface,
+ disabled-unselected-icon-color: mdc-theme-color.$on-surface,
+ unselected-focus-icon-color: $active-border-color,
+ unselected-hover-icon-color: $active-border-color,
+ unselected-icon-color: $on-surface,
+ unselected-pressed-icon-color: $on-surface,
+ selected-focus-icon-color: $color-palette,
+ selected-hover-icon-color: $color-palette,
+ selected-icon-color: $color-palette,
+ selected-pressed-icon-color: $color-palette,
+ ));
+
+ --mat-mdc-radio-ripple-color: #{mdc-theme-color.prop-value(on-surface)};
+
+ // MDC should set the disabled color on the label, but doesn't, so we do it here instead.
+ .mdc-radio--disabled + label {
+ color: theming.get-color-from-palette($foreground, disabled-text);
+ }
+
+ --mat-mdc-radio-checked-ripple-color: #{$color-palette};
+ }
+}
diff --git a/src/material/radio/_radio-theme.scss b/src/material/radio/_radio-theme.scss
index 42d26cb134fd..005a94cbcd5a 100644
--- a/src/material/radio/_radio-theme.scss
+++ b/src/material/radio/_radio-theme.scss
@@ -1,70 +1,32 @@
-@use 'sass:map';
-@use '@material/theme/theme-color' as mdc-theme-color;
-@use '@material/radio/radio-theme' as mdc-radio-theme;
@use '@material/radio/radio' as mdc-radio;
+@use '@material/radio/radio-theme' as mdc-radio-theme;
@use '@material/form-field' as mdc-form-field;
-@use '../core/theming/theming';
@use '../core/mdc-helpers/mdc-helpers';
+@use '../core/theming/theming';
@use '../core/typography/typography';
-@use '../core/theming/palette';
-
-@mixin _color-palette($color-palette) {
- @include mdc-radio-theme.theme((
- selected-focus-icon-color: $color-palette,
- selected-hover-icon-color: $color-palette,
- selected-icon-color: $color-palette,
- selected-pressed-icon-color: $color-palette,
- ));
-
- --mat-mdc-radio-checked-ripple-color: #{$color-palette};
-}
+@use './radio-private';
+@use 'sass:map';
@mixin color($config-or-theme) {
$config: theming.get-color-config($config-or-theme);
$primary: theming.get-color-from-palette(map.get($config, primary));
$accent: theming.get-color-from-palette(map.get($config, accent));
$warn: theming.get-color-from-palette(map.get($config, warn));
- $foreground: map.get($config, foreground);
@include mdc-helpers.using-mdc-theme($config) {
- $on-surface: rgba(mdc-theme-color.$on-surface, 0.54);
- $is-dark: map.get($config, is-dark);
- $active-border-color: if(
- $is-dark,
- theming.get-color-from-palette(palette.$gray-palette, 200),
- theming.get-color-from-palette(palette.$gray-palette, 900)
- );
-
.mat-mdc-radio-button {
@include mdc-form-field.core-styles($query: mdc-helpers.$mdc-theme-styles-query);
- @include mdc-radio-theme.theme((
- // The disabled colors don't use the `rgba` version, because
- // MDC applies a separate opacity to disabled buttons.
- disabled-selected-icon-color: mdc-theme-color.$on-surface,
- disabled-unselected-icon-color: mdc-theme-color.$on-surface,
- unselected-focus-icon-color: $active-border-color,
- unselected-hover-icon-color: $active-border-color,
- unselected-icon-color: $on-surface,
- unselected-pressed-icon-color: $on-surface,
- ));
-
- --mat-mdc-radio-ripple-color: #{mdc-theme-color.prop-value(on-surface)};
-
- // MDC should set the disabled color on the label, but doesn't, so we do it here instead.
- .mdc-radio--disabled + label {
- color: theming.get-color-from-palette($foreground, disabled-text);
- }
&.mat-primary {
- @include _color-palette($primary);
+ @include radio-private.private-radio-color($config, $primary);
}
&.mat-accent {
- @include _color-palette($accent);
+ @include radio-private.private-radio-color($config, $accent);
}
&.mat-warn {
- @include _color-palette($warn);
+ @include radio-private.private-radio-color($config, $warn);
}
}
}
diff --git a/src/material/radio/radio.scss b/src/material/radio/radio.scss
index e24b05f8a507..724c83d0cd95 100644
--- a/src/material/radio/radio.scss
+++ b/src/material/radio/radio.scss
@@ -6,6 +6,7 @@
@use '@material/ripple' as mdc-ripple;
@use '../core/mdc-helpers/mdc-helpers';
@use '../core/style/layout-common';
+@use './radio-private';
@include mdc-helpers.disable-mdc-fallback-declarations {
@@ -18,22 +19,7 @@
// 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-helpers.disable-mdc-fallback-declarations {
- @include mdc-radio-theme.theme-styles(map.merge(mdc-radio-theme.$light-theme, (
- // Exclude the styles we don't need.
- selected-focus-state-layer-color: null,
- selected-focus-state-layer-opacity: null,
- selected-hover-state-layer-color: null,
- selected-hover-state-layer-opacity: null,
- selected-pressed-state-layer-color: null,
- selected-pressed-state-layer-opacity: null,
- unselected-focus-icon-color: null,
- unselected-focus-state-layer-color: null,
- unselected-focus-state-layer-opacity: null,
- unselected-hover-state-layer-color: null,
- unselected-hover-state-layer-opacity: null,
- unselected-pressed-state-layer-color: null,
- unselected-pressed-state-layer-opacity: null,
- )));
+ @include mdc-radio-theme.theme-styles(radio-private.$private-radio-theme-config);
// TODO(crisbeto): this should be included by MDC's `theme-styles`, but it isn't currently.
@include mdc-radio-theme.focus-indicator-color(
diff --git a/tools/public_api_guard/material/list-testing.md b/tools/public_api_guard/material/list-testing.md
index 304935fd1001..8f85468dbc2f 100644
--- a/tools/public_api_guard/material/list-testing.md
+++ b/tools/public_api_guard/material/list-testing.md
@@ -11,7 +11,7 @@ import { ContentContainerComponentHarness } from '@angular/cdk/testing';
import { DividerHarnessFilters } from '@angular/material/divider/testing';
import { HarnessPredicate } from '@angular/cdk/testing';
import { MatDividerHarness } from '@angular/material/divider/testing';
-import { MatListOptionCheckboxPosition } from '@angular/material/list';
+import { MatListOptionTogglePosition } from '@angular/material/list';
// @public (undocumented)
export interface ActionListHarnessFilters extends BaseHarnessFilters {
@@ -102,7 +102,8 @@ export class MatListOptionHarness extends MatListItemHarnessBase {
blur(): Promise;
deselect(): Promise;
focus(): Promise;
- getCheckboxPosition(): Promise;
+ getCheckboxPosition(): Promise;
+ getRadioPosition(): Promise;
static hostSelector: string;
isFocused(): Promise;
isSelected(): Promise;
diff --git a/tools/public_api_guard/material/list.md b/tools/public_api_guard/material/list.md
index da5ae144108e..d04df5b22b18 100644
--- a/tools/public_api_guard/material/list.md
+++ b/tools/public_api_guard/material/list.md
@@ -152,17 +152,20 @@ export class MatListModule {
// @public (undocumented)
export class MatListOption extends MatListItemBase implements ListOption, OnInit, OnDestroy {
constructor(elementRef: ElementRef, ngZone: NgZone, _selectionList: SelectionList, platform: Platform, _changeDetectorRef: ChangeDetectorRef, globalRippleOptions?: RippleGlobalOptions, animationMode?: string);
- checkboxPosition: MatListOptionCheckboxPosition;
+ // @deprecated
+ get checkboxPosition(): MatListOptionTogglePosition;
+ set checkboxPosition(value: MatListOptionTogglePosition);
get color(): ThemePalette;
set color(newValue: ThemePalette);
focus(): void;
- _getCheckboxPosition(): MatListOptionCheckboxPosition;
getLabel(): string;
+ _getTogglePosition(): MatListOptionTogglePosition;
// (undocumented)
_handleBlur(): void;
- _hasCheckboxAt(position: MatListOptionCheckboxPosition): boolean;
+ _hasCheckboxAt(position: MatListOptionTogglePosition): boolean;
_hasIconsOrAvatarsAt(position: 'before' | 'after'): boolean;
_hasProjected(type: 'icons' | 'avatars', position: 'before' | 'after'): boolean;
+ _hasRadioAt(position: MatListOptionTogglePosition): boolean;
// (undocumented)
_lines: QueryList;
_markForCheck(): void;
@@ -179,18 +182,21 @@ export class MatListOption extends MatListItemBase implements ListOption, OnInit
_titles: QueryList;
toggle(): void;
_toggleOnInteraction(): void;
+ togglePosition: MatListOptionTogglePosition;
// (undocumented)
_unscopedContent: ElementRef;
get value(): any;
set value(newValue: any);
// (undocumented)
- static ɵcmp: i0.ɵɵComponentDeclaration;
+ static ɵcmp: i0.ɵɵComponentDeclaration;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration;
}
// @public
-export type MatListOptionCheckboxPosition = 'before' | 'after';
+type MatListOptionTogglePosition = 'before' | 'after';
+export { MatListOptionTogglePosition as MatListOptionCheckboxPosition }
+export { MatListOptionTogglePosition }
// @public
export class MatListSubheaderCssMatStyler {