Skip to content

Commit 42bf4a5

Browse files
committed
refactor(material-experimental/mdc-list): no longer use deprecated styles
We recently switched the MDC list to deprecated styles as the MDC team started reworking the MDC list and our usage is not compatible. With this change, we start using the standard non-deprecated MDC list styles. This allows us to simplify a few custom CSS overrides due the new MDC list API being more aligned with the API we want to support for backwards comaptibility with the non-MDC list (e.g. per list-item icons and avatars instead of it being a per-list setting).
1 parent 382b1b7 commit 42bf4a5

21 files changed

+243
-188
lines changed

src/dev-app/mdc-list/mdc-list-demo.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ export class MdcListDemo {
3535
from: 'Nancy',
3636
subject: 'Brunch?',
3737
message: 'Did you want to go on Sunday? I was thinking that might work.',
38-
image: 'https://angular.io/generated/images/bios/julie-ralph.jpg'
38+
image: 'https://angular.io/generated/images/bios/cindygreenekaplan.jpg'
3939
},
4040
{
4141
from: 'Mary',
4242
subject: 'Summer BBQ',
4343
message: 'Wish I could come, but I have some prior obligations.',
44-
image: 'https://angular.io/generated/images/bios/juleskremer.jpg'
44+
image: 'https://angular.io/generated/images/bios/annieyw.jpg'
4545
},
4646
{
4747
from: 'Bobby',

src/material-experimental/mdc-list/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ sass_binary(
6666
"external/npm/node_modules",
6767
],
6868
deps = [
69+
":mdc_list_scss_lib",
6970
"//src/material-experimental/mdc-helpers:mdc_helpers_scss_lib",
7071
"//src/material-experimental/mdc-helpers:mdc_scss_deps_lib",
7172
],

src/material-experimental/mdc-list/_interactive-list-theme.scss

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,29 @@
66
// has integrated styles for these states but relies on their complex ripples for it.
77
@mixin private-interactive-list-item-state-colors($config) {
88
$is-dark-theme: map.get($config, is-dark);
9-
$state-opacities:
10-
if($is-dark-theme, mdc-ripple.$light-ink-opacities, mdc-ripple.$dark-ink-opacities);
9+
$active-base-color: if($is-dark-theme, white, black);
10+
$selected-color: theming.get-color-from-palette(map.get($config, primary));
1111

1212
.mat-mdc-list-item-interactive {
1313
&::before {
14-
background: if($is-dark-theme, white, black);
14+
background: $active-base-color;
1515
}
1616

17-
&.mdc-deprecated-list-item--selected::before {
18-
background: theming.get-color-from-palette(map.get($config, primary));
19-
opacity: map.get($state-opacities, selected);
17+
&.mdc-list-item--selected::before {
18+
background: $selected-color;
19+
opacity: mdc-ripple.states-opacity($selected-color, selected);
2020
}
2121

2222
&:focus::before {
23-
opacity: map.get($state-opacities, focus);
23+
opacity: mdc-ripple.states-opacity($active-base-color, focus);
2424
}
2525
}
2626

27-
// MDC still shows focus/selected state if the option is disabled. Just the hover
28-
// styles should not show up.
29-
.mat-mdc-list-item-interactive:not(.mdc-deprecated-list-item--disabled) {
27+
// MDC still shows focus/selected state if the item is disabled.
28+
// Just hover styles should not show up for disabled items.
29+
.mat-mdc-list-item-interactive:not(.mdc-list-item--disabled) {
3030
&:hover::before {
31-
opacity: map.get($state-opacities, hover);
31+
opacity: mdc-ripple.states-opacity($active-base-color, hover);
3232
}
3333
}
3434
}

src/material-experimental/mdc-list/_list-option-theme.scss

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,27 @@
1-
@use '@material/theme/theme' as mdc-theme;
21
@use '@material/checkbox' as mdc-checkbox;
3-
@use '@material/list' as mdc-list;
42
@use '../mdc-checkbox/checkbox-theme';
53
@use '../mdc-helpers/mdc-helpers';
6-
4+
@use './list-option-trailing-avatar-compat';
75

86
// Mixin that overrides the selected item and checkbox colors for list options. By
97
// default, the MDC list uses the `primary` color for list items. The MDC checkbox
108
// inside list options by default uses the `primary` color too.
119
@mixin private-list-option-color-override($color) {
12-
& .mdc-deprecated-list-item__meta, & .mdc-deprecated-list-item__graphic {
10+
& .mdc-list-item__start, & .mdc-list-item__end {
1311
@include checkbox-theme.private-checkbox-styles-with-color($color);
1412
}
15-
16-
&.mdc-deprecated-list-item--selected {
17-
@include mdc-list.deprecated-item-primary-text-ink-color($color);
18-
@include mdc-list.deprecated-item-graphic-ink-color($color);
19-
20-
&::before {
21-
@include mdc-theme.prop(background, $color);
22-
}
23-
}
2413
}
2514

2615
@mixin private-list-option-density-styles($density-scale) {
27-
.mat-mdc-list-option {
28-
.mdc-deprecated-list-item__meta, .mdc-deprecated-list-item__graphic {
29-
.mdc-checkbox {
30-
@include mdc-checkbox.density($density-scale, $query: mdc-helpers.$mat-base-styles-query);
31-
}
32-
}
33-
}
16+
@include list-option-trailing-avatar-compat.density-styles($density-scale);
3417
}
3518

3619
@mixin private-list-option-typography-styles() {
20+
@include list-option-trailing-avatar-compat.core-styles(
21+
$query: mdc-helpers.$mat-typography-styles-query);
22+
3723
.mat-mdc-list-option {
38-
.mdc-deprecated-list-item__meta, .mdc-deprecated-list-item__graphic {
24+
.mdc-list-item__start, .mdc-list-item__end {
3925
@include mdc-checkbox.without-ripple($query: mdc-helpers.$mat-typography-styles-query);
4026
}
4127
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
@use '@material/typography/typography';
2+
@use '@material/feature-targeting/feature-targeting';
3+
@use '@material/density/functions' as density-functions;
4+
@use '@material/list/evolution-mixins' as mdc-list;
5+
@use '@material/list/evolution-variables' as mdc-list-variables;
6+
7+
// For compatibility with the non-MDC selection list, we support avatars that are
8+
// shown at the end of the list option. This is not supported by the MDC list as the
9+
// spec only defines avatars at the beginning of a list item. For selection list options,
10+
// we support changing the checkbox position to `before`. This results in the avatar from
11+
// the list start being moved to the end. Similar to MDC's `--trailing-icon` class, we
12+
// implement a `--trailing-avatar` class that is based on the original `--leading-avatar`
13+
// implementation. See: https://github.com/material-components/material-components-web/blob/3f342c3f4715fd3587f327ce4ea6b5dd314c5c55/packages/mdc-list/_evolution-mixins.scss#L198-L217
14+
15+
@mixin core-styles($query) {
16+
$feat-structure: feature-targeting.create-target($query, structure);
17+
18+
.mat-mdc-list-option-with-trailing-avatar {
19+
@include mdc-list.item-end-spacing(16px, $query: $query);
20+
@include mdc-list.item-end-size(40px, $query: $query);
21+
22+
&.mdc-list-item--with-two-lines {
23+
.mdc-list-item__primary-text {
24+
@include typography.text-baseline($top: 32px, $bottom: 20px, $query: $query);
25+
}
26+
}
27+
28+
.mdc-list-item__end {
29+
@include feature-targeting.targets($feat-structure) {
30+
border-radius: 50%;
31+
}
32+
}
33+
}
34+
}
35+
36+
@mixin density-styles($density-scale) {
37+
$one-line-tall-height: density-functions.prop-value(
38+
$density-config: mdc-list-variables.$one-line-item-tall-density-config,
39+
$density-scale: $density-scale,
40+
$property-name: height,
41+
);
42+
43+
$two-line-tall-height: density-functions.prop-value(
44+
$density-config: mdc-list-variables.$two-line-item-tall-density-config,
45+
$density-scale: $density-scale,
46+
$property-name: height,
47+
);
48+
49+
.mat-mdc-list-option-with-trailing-avatar {
50+
@include mdc-list.one-line-item-height($one-line-tall-height);
51+
@include mdc-list.two-line-item-height($two-line-tall-height);
52+
}
53+
}

src/material-experimental/mdc-list/_list-theme.scss

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
@use '@material/density' as mdc-density;
2-
@use '@material/list' as mdc-list;
1+
@use '@material/list/evolution-mixins' as mdc-list;
32
@use './interactive-list-theme';
43
@use './list-option-theme';
54
@use '../mdc-helpers/mdc-helpers';
@@ -18,7 +17,7 @@
1817
@include interactive-list-theme.private-interactive-list-item-state-colors($config);
1918

2019
@include mdc-helpers.mat-using-mdc-theme($config) {
21-
@include mdc-list.deprecated-without-ripple($query: mdc-helpers.$mat-theme-styles-query);
20+
@include mdc-list.without-ripple($query: mdc-helpers.$mat-theme-styles-query);
2221

2322
.mat-mdc-list-option {
2423
@include list-option-theme.private-list-option-color-override(primary);
@@ -34,19 +33,11 @@
3433

3534
@mixin density($config-or-theme) {
3635
$density-scale: theming.get-density-config($config-or-theme);
37-
$height: mdc-density.prop-value(
38-
$density-config: mdc-list.$deprecated-single-line-density-config,
39-
$density-scale: $density-scale,
40-
$property-name: height,
41-
);
4236

43-
// MDC list provides a mixin called `mdc-list-single-line-density`, but we cannot use
44-
// that mixin, as the generated generated density styles are scoped to
45-
// `.mdc-deprecated-list-item`, while the styles should actually only affect single-line list
46-
// items. This has been reported as a bug in the MDC repository:
47-
// https://github.com/material-components/material-components-web/issues/5737.
48-
.mat-mdc-list-item-single-line {
49-
@include mdc-list.deprecated-single-line-height($height);
37+
.mat-mdc-list-item {
38+
@include mdc-list.one-line-item-density($density-scale);
39+
@include mdc-list.two-line-item-density($density-scale);
40+
@include mdc-list.three-line-item-density($density-scale);
5041
}
5142

5243
@include list-option-theme.private-list-option-density-styles($density-scale);
@@ -56,7 +47,7 @@
5647
$config: typography.private-typography-to-2018-config(
5748
theming.get-typography-config($config-or-theme));
5849
@include mdc-helpers.mat-using-mdc-typography($config) {
59-
@include mdc-list.deprecated-without-ripple($query: mdc-helpers.$mat-typography-styles-query);
50+
@include mdc-list.without-ripple($query: mdc-helpers.$mat-typography-styles-query);
6051
@include list-option-theme.private-list-option-typography-styles();
6152
}
6253
}

src/material-experimental/mdc-list/action-list.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {MatListBase} from './list-base';
1414
exportAs: 'matActionList',
1515
template: '<ng-content></ng-content>',
1616
host: {
17-
'class': 'mat-mdc-action-list mat-mdc-list-base mdc-deprecated-list',
17+
'class': 'mat-mdc-action-list mat-mdc-list-base mdc--list',
1818
},
1919
styleUrls: ['list.css'],
2020
encapsulation: ViewEncapsulation.None,

src/material-experimental/mdc-list/list-base.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,6 @@ export abstract class MatListItemBase implements AfterContentInit, OnDestroy, Ri
6565
private _disableRipple: boolean = false;
6666

6767
/** Whether the list-item is disabled. */
68-
@HostBinding('class.mdc-deprecated-list-item--disabled')
6968
@HostBinding('class.mdc-list-item--disabled')
7069
@HostBinding('attr.aria-disabled')
7170
@Input()
@@ -155,11 +154,17 @@ export abstract class MatListItemBase implements AfterContentInit, OnDestroy, Ri
155154
this._subscriptions.add(this.lines.changes.pipe(startWith(this.lines))
156155
.subscribe((lines: QueryList<ElementRef<Element>>) => {
157156
toggleClass(this._hostElement, 'mat-mdc-list-item-single-line', lines.length <= 1);
157+
toggleClass(this._hostElement, 'mdc-list-item--with-one-line', lines.length <= 1);
158+
158159
lines.forEach((line: ElementRef<Element>, index: number) => {
160+
toggleClass(
161+
this._hostElement, 'mdc-list-item--with-two-lines', lines.length === 2);
162+
toggleClass(
163+
this._hostElement, 'mdc-list-item--with-three-lines', lines.length === 3);
159164
toggleClass(line.nativeElement,
160-
'mdc-deprecated-list-item__primary-text', index === 0 && lines.length > 1);
165+
'mdc-list-item__primary-text', index === 0 && lines.length > 1);
161166
toggleClass(
162-
line.nativeElement, 'mdc-deprecated-list-item__secondary-text', index !== 0);
167+
line.nativeElement, 'mdc-list-item__secondary-text', index !== 0);
163168
});
164169
setLines(lines, this._elementRef, 'mat-mdc');
165170
}));

src/material-experimental/mdc-list/list-item.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@
22

33
<!-- If lines were explicitly given, use those as the text. -->
44
<ng-container *ngIf="lines.length">
5-
<span class="mdc-deprecated-list-item__text"><ng-content select="[mat-line],[matLine]"></ng-content></span>
5+
<span class="mdc-list-item__content"><ng-content select="[mat-line],[matLine]"></ng-content></span>
66
</ng-container>
77

88
<!--
99
If lines were not explicitly given, assume the remaining content is the text, otherwise assume it
10-
is an action that belongs in the "meta" section.
10+
is an action that belongs in the "end" section.
1111
-->
12-
<span [class.mdc-deprecated-list-item__text]="!lines.length"
13-
[class.mdc-deprecated-list-item__meta]="lines.length" #text>
12+
<span [class.mdc-list-item__content]="!lines.length"
13+
[class.mdc-list-item__end]="lines.length" #text>
1414
<ng-content></ng-content>
1515
</span>
1616

src/material-experimental/mdc-list/list-option.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,26 +25,26 @@
2525
</ng-template>
2626

2727
<!-- Container for the checkbox at start. -->
28-
<span class="mdc-deprecated-list-item__graphic mat-mdc-list-option-checkbox-before"
29-
*ngIf="_shouldShowCheckboxAt('before')">
28+
<span class="mdc-list-item__start mat-mdc-list-option-checkbox-before"
29+
*ngIf="_hasCheckboxAt('before')">
3030
<ng-template [ngTemplateOutlet]="checkbox"></ng-template>
3131
</span>
3232
<!-- Conditionally renders icons/avatars before the list item text. -->
33-
<ng-template [ngIf]="_shouldShowIconsAndAvatarsAt('before')">
33+
<ng-template [ngIf]="_hasIconsOrAvatarsAt('before')">
3434
<ng-template [ngTemplateOutlet]="icons"></ng-template>
3535
</ng-template>
3636

3737
<!-- Text -->
38-
<span class="mdc-deprecated-list-item__text" #text>
38+
<span class="mdc-list-item__content" #text>
3939
<ng-content></ng-content>
4040
</span>
4141

4242
<!-- Container for the checkbox at the end. -->
43-
<span class="mdc-deprecated-list-item__meta" *ngIf="_shouldShowCheckboxAt('after')">
43+
<span class="mdc-list-item__end" *ngIf="_hasCheckboxAt('after')">
4444
<ng-template [ngTemplateOutlet]="checkbox"></ng-template>
4545
</span>
4646
<!-- Conditionally renders icons/avatars after the list item text. -->
47-
<ng-template [ngIf]="_shouldShowIconsAndAvatarsAt('after')">
47+
<ng-template [ngIf]="_hasIconsOrAvatarsAt('after')">
4848
<ng-template [ngTemplateOutlet]="icons"></ng-template>
4949
</ng-template>
5050

src/material-experimental/mdc-list/list-option.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
@use '@material/list' as mdc-list;
33
@use '../mdc-helpers/mdc-helpers';
44
@use '../../cdk/a11y';
5+
@use './list-option-trailing-avatar-compat';
56

67
// The MDC-based list-option uses the MDC checkbox for the selection indicators.
78
// We need to ensure that the checkbox styles are included for the list-option.
89
@include mdc-checkbox.without-ripple($query: mdc-helpers.$mat-base-styles-query);
910

11+
// For compatibility with the non-MDC list, we support avatars that are shown at the end
12+
// of the list option. We create a class similar to MDC's `--trailing-icon` one.
13+
@include list-option-trailing-avatar-compat.core-styles($query: mdc-helpers.$mat-base-styles-query);
14+
1015
// The internal checkbox is purely decorative, but because it's an `input`, the user can still
1116
// focus it by tabbing or clicking. Furthermore, `mat-list-option` has the `option` role which
1217
// doesn't allow a nested `input`. We use `display: none` both to remove it from the tab order

src/material-experimental/mdc-list/list-option.ts

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,21 @@ export interface SelectionList extends MatListBase {
6262
exportAs: 'matListOption',
6363
styleUrls: ['list-option.css'],
6464
host: {
65-
'class': 'mat-mdc-list-item mat-mdc-list-option mdc-deprecated-list-item',
65+
'class': 'mat-mdc-list-item mat-mdc-list-option mdc-list-item',
6666
'role': 'option',
6767
// As per MDC, only list items in single selection mode should receive the `--selected`
6868
// class. For multi selection, the checkbox is used as indicator.
69-
'[class.mdc-deprecated-list-item--selected]': 'selected && !_selectionList.multiple',
70-
'[class.mat-mdc-list-item-with-avatar]': '_hasIconOrAvatar()',
69+
'[class.mdc-list-item--selected]': 'selected && !_selectionList.multiple',
70+
// Based on the checkbox position and whether there are icons or avatars, we apply MDC's
71+
// list-item `--leading` and `--trailing` classes.
72+
'[class.mdc-list-item--with-leading-avatar]': '_hasProjected("avatars", "before")',
73+
'[class.mdc-list-item--with-leading-icon]': '_hasProjected("icons", "before")',
74+
'[class.mdc-list-item--with-trailing-icon]': '_hasProjected("icons", "after")',
75+
'[class.mat-mdc-list-option-with-trailing-avatar]': '_hasProjected("avatars", "after")',
76+
// Based on the checkbox position, we apply the `--leading` or `--trailing` MDC classes
77+
// which ensure that the checkbox is positioned correctly within the list item.
78+
'[class.mdc-list-item--with-leading-checkbox]': '_hasCheckboxAt("before")',
79+
'[class.mdc-list-item--with-trailing-checkbox]': '_hasCheckboxAt("after")',
7180
'[class.mat-accent]': 'color !== "primary" && color !== "warn"',
7281
'[class.mat-warn]': 'color === "warn"',
7382
'(blur)': '_handleBlur()',
@@ -188,14 +197,22 @@ export class MatListOption extends MatListItemBase implements ListOption, OnInit
188197
this._hostElement.focus();
189198
}
190199

191-
/** Whether the checkbox should be shown at the given position. */
192-
_shouldShowCheckboxAt(position: MatListOptionCheckboxPosition): boolean {
200+
/** Whether a checkbox is shown at the given position. */
201+
_hasCheckboxAt(position: MatListOptionCheckboxPosition): boolean {
193202
return this._selectionList.multiple && this._getCheckboxPosition() === position;
194203
}
195204

196-
/** Whether icons and avatars should be shown at the given position. */
197-
_shouldShowIconsAndAvatarsAt(position: 'before'|'after'): boolean {
198-
return this._getCheckboxPosition() !== position && this._hasIconOrAvatar();
205+
/** Whether icons or avatars are shown at the given position. */
206+
_hasIconsOrAvatarsAt(position: 'before'|'after'): boolean {
207+
return this._hasProjected('icons', position) || this._hasProjected('avatars', position);
208+
}
209+
210+
/** Gets whether the given type of element is projected at the specified position. */
211+
_hasProjected(type: 'icons'|'avatars', position: 'before'|'after'): boolean {
212+
// If the checkbox is shown at the specified position, neither icons or
213+
// avatars can be shown at the position.
214+
return this._getCheckboxPosition() !== position &&
215+
(type === 'avatars' ? this._avatars.length !== 0 : this._icons.length !== 0);
199216
}
200217

201218
_handleBlur() {

0 commit comments

Comments
 (0)