From 81f2f0a565d64fe648db583ffe5217e4873ab01a Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Fri, 16 Apr 2021 21:53:03 +0200 Subject: [PATCH] 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). --- package.json | 96 +- packages.bzl | 2 +- src/dev-app/list/list-demo.ts | 4 +- src/dev-app/mdc-list/mdc-list-demo.ts | 4 +- .../mdc-list/BUILD.bazel | 1 + .../mdc-list/_interactive-list-theme.scss | 22 +- .../mdc-list/_list-option-theme.scss | 28 +- .../_list-option-trailing-avatar-compat.scss | 53 ++ .../mdc-list/_list-theme.scss | 23 +- .../mdc-list/action-list.ts | 2 +- .../mdc-list/list-base.ts | 11 +- .../mdc-list/list-item.html | 8 +- .../mdc-list/list-option.html | 12 +- .../mdc-list/list-option.scss | 5 + .../mdc-list/list-option.ts | 33 +- .../mdc-list/list-styling.ts | 14 +- src/material-experimental/mdc-list/list.scss | 112 +-- .../mdc-list/list.spec.ts | 23 +- src/material-experimental/mdc-list/list.ts | 12 +- .../mdc-list/nav-list.ts | 2 +- .../mdc-list/selection-list.spec.ts | 85 +- .../mdc-list/selection-list.ts | 2 +- .../testing/list-item-harness-base.ts | 2 +- .../testing/selection-list-harness.ts | 2 +- yarn.lock | 835 +++--------------- 25 files changed, 389 insertions(+), 1004 deletions(-) create mode 100644 src/material-experimental/mdc-list/_list-option-trailing-avatar-compat.scss diff --git a/package.json b/package.json index a8da1645b367..95afbc651d38 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@types/googlemaps": "^3.43.1", "@types/youtube": "^0.0.42", "core-js-bundle": "^3.8.2", - "material-components-web": "^12.0.0-canary.a23ecb682.0", + "material-components-web": "^12.0.0-canary.00b5899dc.0", "rxjs": "^6.5.3", "rxjs-tslint-rules": "^4.33.1", "systemjs": "0.19.43", @@ -95,53 +95,53 @@ "@bazel/terser": "3.5.0", "@bazel/typescript": "3.5.0", "@firebase/app-types": "^0.6.1", - "@material/animation": "^12.0.0-canary.a23ecb682.0", - "@material/auto-init": "^12.0.0-canary.a23ecb682.0", - "@material/banner": "^12.0.0-canary.a23ecb682.0", - "@material/base": "^12.0.0-canary.a23ecb682.0", - "@material/button": "^12.0.0-canary.a23ecb682.0", - "@material/card": "^12.0.0-canary.a23ecb682.0", - "@material/checkbox": "^12.0.0-canary.a23ecb682.0", - "@material/chips": "^12.0.0-canary.a23ecb682.0", - "@material/circular-progress": "^12.0.0-canary.a23ecb682.0", - "@material/data-table": "^12.0.0-canary.a23ecb682.0", - "@material/density": "^12.0.0-canary.a23ecb682.0", - "@material/dialog": "^12.0.0-canary.a23ecb682.0", - "@material/dom": "^12.0.0-canary.a23ecb682.0", - "@material/drawer": "^12.0.0-canary.a23ecb682.0", - "@material/elevation": "^12.0.0-canary.a23ecb682.0", - "@material/fab": "^12.0.0-canary.a23ecb682.0", - "@material/feature-targeting": "^12.0.0-canary.a23ecb682.0", - "@material/floating-label": "^12.0.0-canary.a23ecb682.0", - "@material/form-field": "^12.0.0-canary.a23ecb682.0", - "@material/icon-button": "^12.0.0-canary.a23ecb682.0", - "@material/image-list": "^12.0.0-canary.a23ecb682.0", - "@material/layout-grid": "^12.0.0-canary.a23ecb682.0", - "@material/line-ripple": "^12.0.0-canary.a23ecb682.0", - "@material/linear-progress": "^12.0.0-canary.a23ecb682.0", - "@material/list": "^12.0.0-canary.a23ecb682.0", - "@material/menu": "^12.0.0-canary.a23ecb682.0", - "@material/menu-surface": "^12.0.0-canary.a23ecb682.0", - "@material/notched-outline": "^12.0.0-canary.a23ecb682.0", - "@material/radio": "^12.0.0-canary.a23ecb682.0", - "@material/ripple": "^12.0.0-canary.a23ecb682.0", - "@material/rtl": "^12.0.0-canary.a23ecb682.0", - "@material/segmented-button": "^12.0.0-canary.a23ecb682.0", - "@material/select": "^12.0.0-canary.a23ecb682.0", - "@material/shape": "^12.0.0-canary.a23ecb682.0", - "@material/slider": "^12.0.0-canary.a23ecb682.0", - "@material/snackbar": "^12.0.0-canary.a23ecb682.0", - "@material/switch": "^12.0.0-canary.a23ecb682.0", - "@material/tab": "^12.0.0-canary.a23ecb682.0", - "@material/tab-bar": "^12.0.0-canary.a23ecb682.0", - "@material/tab-indicator": "^12.0.0-canary.a23ecb682.0", - "@material/tab-scroller": "^12.0.0-canary.a23ecb682.0", - "@material/textfield": "^12.0.0-canary.a23ecb682.0", - "@material/theme": "^12.0.0-canary.a23ecb682.0", - "@material/tooltip": "^12.0.0-canary.a23ecb682.0", - "@material/top-app-bar": "^12.0.0-canary.a23ecb682.0", - "@material/touch-target": "^12.0.0-canary.a23ecb682.0", - "@material/typography": "^12.0.0-canary.a23ecb682.0", + "@material/animation": "^12.0.0-canary.00b5899dc.0", + "@material/auto-init": "^12.0.0-canary.00b5899dc.0", + "@material/banner": "^12.0.0-canary.00b5899dc.0", + "@material/base": "^12.0.0-canary.00b5899dc.0", + "@material/button": "^12.0.0-canary.00b5899dc.0", + "@material/card": "^12.0.0-canary.00b5899dc.0", + "@material/checkbox": "^12.0.0-canary.00b5899dc.0", + "@material/chips": "^12.0.0-canary.00b5899dc.0", + "@material/circular-progress": "^12.0.0-canary.00b5899dc.0", + "@material/data-table": "^12.0.0-canary.00b5899dc.0", + "@material/density": "^12.0.0-canary.00b5899dc.0", + "@material/dialog": "^12.0.0-canary.00b5899dc.0", + "@material/dom": "^12.0.0-canary.00b5899dc.0", + "@material/drawer": "^12.0.0-canary.00b5899dc.0", + "@material/elevation": "^12.0.0-canary.00b5899dc.0", + "@material/fab": "^12.0.0-canary.00b5899dc.0", + "@material/feature-targeting": "^12.0.0-canary.00b5899dc.0", + "@material/floating-label": "^12.0.0-canary.00b5899dc.0", + "@material/form-field": "^12.0.0-canary.00b5899dc.0", + "@material/icon-button": "^12.0.0-canary.00b5899dc.0", + "@material/image-list": "^12.0.0-canary.00b5899dc.0", + "@material/layout-grid": "^12.0.0-canary.00b5899dc.0", + "@material/line-ripple": "^12.0.0-canary.00b5899dc.0", + "@material/linear-progress": "^12.0.0-canary.00b5899dc.0", + "@material/list": "^12.0.0-canary.00b5899dc.0", + "@material/menu": "^12.0.0-canary.00b5899dc.0", + "@material/menu-surface": "^12.0.0-canary.00b5899dc.0", + "@material/notched-outline": "^12.0.0-canary.00b5899dc.0", + "@material/radio": "^12.0.0-canary.00b5899dc.0", + "@material/ripple": "^12.0.0-canary.00b5899dc.0", + "@material/rtl": "^12.0.0-canary.00b5899dc.0", + "@material/segmented-button": "^12.0.0-canary.00b5899dc.0", + "@material/select": "^12.0.0-canary.00b5899dc.0", + "@material/shape": "^12.0.0-canary.00b5899dc.0", + "@material/slider": "^12.0.0-canary.00b5899dc.0", + "@material/snackbar": "^12.0.0-canary.00b5899dc.0", + "@material/switch": "^12.0.0-canary.00b5899dc.0", + "@material/tab": "^12.0.0-canary.00b5899dc.0", + "@material/tab-bar": "^12.0.0-canary.00b5899dc.0", + "@material/tab-indicator": "^12.0.0-canary.00b5899dc.0", + "@material/tab-scroller": "^12.0.0-canary.00b5899dc.0", + "@material/textfield": "^12.0.0-canary.00b5899dc.0", + "@material/theme": "^12.0.0-canary.00b5899dc.0", + "@material/tooltip": "^12.0.0-canary.00b5899dc.0", + "@material/top-app-bar": "^12.0.0-canary.00b5899dc.0", + "@material/touch-target": "^12.0.0-canary.00b5899dc.0", + "@material/typography": "^12.0.0-canary.00b5899dc.0", "@octokit/rest": "18.3.5", "@rollup/plugin-babel": "^5.3.0", "@rollup/plugin-commonjs": "^18.0.0", diff --git a/packages.bzl b/packages.bzl index 378f3b6db6a2..e2e56ebf586b 100644 --- a/packages.bzl +++ b/packages.bzl @@ -2,7 +2,7 @@ # all in-sync. This map is passed to each ng_package rule to stamp out the appropriate # version for the placeholders. ANGULAR_PACKAGE_VERSION = "^12.0.0 || ^13.0.0-0" -MDC_PACKAGE_VERSION = "^12.0.0-canary.a23ecb682.0" +MDC_PACKAGE_VERSION = "^12.0.0-canary.00b5899dc.0" TSLIB_PACKAGE_VERSION = "^2.1.0" RXJS_PACKAGE_VERSION = "^6.5.3" diff --git a/src/dev-app/list/list-demo.ts b/src/dev-app/list/list-demo.ts index 42a691b852ed..34aeb757fb69 100644 --- a/src/dev-app/list/list-demo.ts +++ b/src/dev-app/list/list-demo.ts @@ -35,13 +35,13 @@ export class ListDemo { from: 'Nancy', subject: 'Brunch?', message: 'Did you want to go on Sunday? I was thinking that might work.', - image: 'https://angular.io/generated/images/bios/julie-ralph.jpg' + image: 'https://angular.io/generated/images/bios/cindygreenekaplan.jpg' }, { from: 'Mary', subject: 'Summer BBQ', message: 'Wish I could come, but I have some prior obligations.', - image: 'https://angular.io/generated/images/bios/juleskremer.jpg' + image: 'https://angular.io/generated/images/bios/twerske.jpg' }, { from: 'Bobby', diff --git a/src/dev-app/mdc-list/mdc-list-demo.ts b/src/dev-app/mdc-list/mdc-list-demo.ts index 4863acbe50e0..7a3e62d175d5 100644 --- a/src/dev-app/mdc-list/mdc-list-demo.ts +++ b/src/dev-app/mdc-list/mdc-list-demo.ts @@ -35,13 +35,13 @@ export class MdcListDemo { from: 'Nancy', subject: 'Brunch?', message: 'Did you want to go on Sunday? I was thinking that might work.', - image: 'https://angular.io/generated/images/bios/julie-ralph.jpg' + image: 'https://angular.io/generated/images/bios/cindygreenekaplan.jpg' }, { from: 'Mary', subject: 'Summer BBQ', message: 'Wish I could come, but I have some prior obligations.', - image: 'https://angular.io/generated/images/bios/juleskremer.jpg' + image: 'https://angular.io/generated/images/bios/twerske.jpg' }, { from: 'Bobby', diff --git a/src/material-experimental/mdc-list/BUILD.bazel b/src/material-experimental/mdc-list/BUILD.bazel index 9b4ecfdf6029..a2aa591e7c94 100644 --- a/src/material-experimental/mdc-list/BUILD.bazel +++ b/src/material-experimental/mdc-list/BUILD.bazel @@ -66,6 +66,7 @@ sass_binary( "external/npm/node_modules", ], deps = [ + ":mdc_list_scss_lib", "//src/material-experimental/mdc-helpers:mdc_helpers_scss_lib", "//src/material-experimental/mdc-helpers:mdc_scss_deps_lib", ], diff --git a/src/material-experimental/mdc-list/_interactive-list-theme.scss b/src/material-experimental/mdc-list/_interactive-list-theme.scss index 84135ba60947..82be8905608c 100644 --- a/src/material-experimental/mdc-list/_interactive-list-theme.scss +++ b/src/material-experimental/mdc-list/_interactive-list-theme.scss @@ -6,29 +6,29 @@ // has integrated styles for these states but relies on their complex ripples for it. @mixin private-interactive-list-item-state-colors($config) { $is-dark-theme: map.get($config, is-dark); - $state-opacities: - if($is-dark-theme, mdc-ripple.$light-ink-opacities, mdc-ripple.$dark-ink-opacities); + $active-base-color: if($is-dark-theme, white, black); + $selected-color: theming.get-color-from-palette(map.get($config, primary)); .mat-mdc-list-item-interactive { &::before { - background: if($is-dark-theme, white, black); + background: $active-base-color; } - &.mdc-deprecated-list-item--selected::before { - background: theming.get-color-from-palette(map.get($config, primary)); - opacity: map.get($state-opacities, selected); + &.mdc-list-item--selected::before { + background: $selected-color; + opacity: mdc-ripple.states-opacity($selected-color, selected); } &:focus::before { - opacity: map.get($state-opacities, focus); + opacity: mdc-ripple.states-opacity($active-base-color, focus); } } - // MDC still shows focus/selected state if the option is disabled. Just the hover - // styles should not show up. - .mat-mdc-list-item-interactive:not(.mdc-deprecated-list-item--disabled) { + // MDC still shows focus/selected state if the item is disabled. + // Just hover styles should not show up for disabled items. + .mat-mdc-list-item-interactive:not(.mdc-list-item--disabled) { &:hover::before { - opacity: map.get($state-opacities, hover); + opacity: mdc-ripple.states-opacity($active-base-color, hover); } } } diff --git a/src/material-experimental/mdc-list/_list-option-theme.scss b/src/material-experimental/mdc-list/_list-option-theme.scss index 642ad8e0dfca..031af6384ace 100644 --- a/src/material-experimental/mdc-list/_list-option-theme.scss +++ b/src/material-experimental/mdc-list/_list-option-theme.scss @@ -1,41 +1,27 @@ -@use '@material/theme/theme' as mdc-theme; @use '@material/checkbox' as mdc-checkbox; -@use '@material/list' as mdc-list; @use '../mdc-checkbox/checkbox-theme'; @use '../mdc-helpers/mdc-helpers'; - +@use './list-option-trailing-avatar-compat'; // 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 private-list-option-color-override($color) { - & .mdc-deprecated-list-item__meta, & .mdc-deprecated-list-item__graphic { + & .mdc-list-item__start, & .mdc-list-item__end { @include checkbox-theme.private-checkbox-styles-with-color($color); } - - &.mdc-deprecated-list-item--selected { - @include mdc-list.deprecated-item-primary-text-ink-color($color); - @include mdc-list.deprecated-item-graphic-ink-color($color); - - &::before { - @include mdc-theme.prop(background, $color); - } - } } @mixin private-list-option-density-styles($density-scale) { - .mat-mdc-list-option { - .mdc-deprecated-list-item__meta, .mdc-deprecated-list-item__graphic { - .mdc-checkbox { - @include mdc-checkbox.density($density-scale, $query: mdc-helpers.$mat-base-styles-query); - } - } - } + @include list-option-trailing-avatar-compat.density-styles($density-scale); } @mixin private-list-option-typography-styles() { + @include list-option-trailing-avatar-compat.core-styles( + $query: mdc-helpers.$mat-typography-styles-query); + .mat-mdc-list-option { - .mdc-deprecated-list-item__meta, .mdc-deprecated-list-item__graphic { + .mdc-list-item__start, .mdc-list-item__end { @include mdc-checkbox.without-ripple($query: mdc-helpers.$mat-typography-styles-query); } } diff --git a/src/material-experimental/mdc-list/_list-option-trailing-avatar-compat.scss b/src/material-experimental/mdc-list/_list-option-trailing-avatar-compat.scss new file mode 100644 index 000000000000..24c84560b408 --- /dev/null +++ b/src/material-experimental/mdc-list/_list-option-trailing-avatar-compat.scss @@ -0,0 +1,53 @@ +@use '@material/typography/typography'; +@use '@material/feature-targeting/feature-targeting'; +@use '@material/density/functions' as density-functions; +@use '@material/list/evolution-mixins' as mdc-list; +@use '@material/list/evolution-variables' as mdc-list-variables; + +// For compatibility with the non-MDC selection list, we support avatars that are +// shown at the end of the list option. This is not supported by the MDC list as the +// spec only defines avatars at the beginning of a list item. For selection list options, +// we support changing the checkbox position to `before`. This results in the avatar from +// the list start being moved to the end. Similar to MDC's `--trailing-icon` class, we +// implement a `--trailing-avatar` class that is based on the original `--leading-avatar` +// implementation. See: https://github.com/material-components/material-components-web/blob/3f342c3f4715fd3587f327ce4ea6b5dd314c5c55/packages/mdc-list/_evolution-mixins.scss#L198-L217 + +@mixin core-styles($query) { + $feat-structure: feature-targeting.create-target($query, structure); + + .mat-mdc-list-option-with-trailing-avatar { + @include mdc-list.item-end-spacing(16px, $query: $query); + @include mdc-list.item-end-size(40px, $query: $query); + + &.mdc-list-item--with-two-lines { + .mdc-list-item__primary-text { + @include typography.text-baseline($top: 32px, $bottom: 20px, $query: $query); + } + } + + .mdc-list-item__end { + @include feature-targeting.targets($feat-structure) { + border-radius: 50%; + } + } + } +} + +@mixin density-styles($density-scale) { + $one-line-tall-height: density-functions.prop-value( + $density-config: mdc-list-variables.$one-line-item-tall-density-config, + $density-scale: $density-scale, + $property-name: height, + ); + + $two-line-tall-height: density-functions.prop-value( + $density-config: mdc-list-variables.$two-line-item-tall-density-config, + $density-scale: $density-scale, + $property-name: height, + ); + + .mat-mdc-list-option-with-trailing-avatar { + @include mdc-list.one-line-item-height($one-line-tall-height); + @include mdc-list.two-line-item-height($two-line-tall-height); + } +} diff --git a/src/material-experimental/mdc-list/_list-theme.scss b/src/material-experimental/mdc-list/_list-theme.scss index bb5e33b9fb8b..ac1eea9c964b 100644 --- a/src/material-experimental/mdc-list/_list-theme.scss +++ b/src/material-experimental/mdc-list/_list-theme.scss @@ -1,5 +1,4 @@ -@use '@material/density' as mdc-density; -@use '@material/list' as mdc-list; +@use '@material/list/evolution-mixins' as mdc-list; @use './interactive-list-theme'; @use './list-option-theme'; @use '../mdc-helpers/mdc-helpers'; @@ -18,7 +17,7 @@ @include interactive-list-theme.private-interactive-list-item-state-colors($config); @include mdc-helpers.mat-using-mdc-theme($config) { - @include mdc-list.deprecated-without-ripple($query: mdc-helpers.$mat-theme-styles-query); + @include mdc-list.without-ripple($query: mdc-helpers.$mat-theme-styles-query); .mat-mdc-list-option { @include list-option-theme.private-list-option-color-override(primary); @@ -34,19 +33,11 @@ @mixin density($config-or-theme) { $density-scale: theming.get-density-config($config-or-theme); - $height: mdc-density.prop-value( - $density-config: mdc-list.$deprecated-single-line-density-config, - $density-scale: $density-scale, - $property-name: height, - ); - // MDC list provides a mixin called `mdc-list-single-line-density`, but we cannot use - // that mixin, as the generated generated density styles are scoped to - // `.mdc-deprecated-list-item`, while the styles should actually only affect single-line list - // items. This has been reported as a bug in the MDC repository: - // https://github.com/material-components/material-components-web/issues/5737. - .mat-mdc-list-item-single-line { - @include mdc-list.deprecated-single-line-height($height); + .mat-mdc-list-item { + @include mdc-list.one-line-item-density($density-scale); + @include mdc-list.two-line-item-density($density-scale); + @include mdc-list.three-line-item-density($density-scale); } @include list-option-theme.private-list-option-density-styles($density-scale); @@ -56,7 +47,7 @@ $config: typography.private-typography-to-2018-config( theming.get-typography-config($config-or-theme)); @include mdc-helpers.mat-using-mdc-typography($config) { - @include mdc-list.deprecated-without-ripple($query: mdc-helpers.$mat-typography-styles-query); + @include mdc-list.without-ripple($query: mdc-helpers.$mat-typography-styles-query); @include list-option-theme.private-list-option-typography-styles(); } } diff --git a/src/material-experimental/mdc-list/action-list.ts b/src/material-experimental/mdc-list/action-list.ts index ed7f2df7d925..44cfd7639330 100644 --- a/src/material-experimental/mdc-list/action-list.ts +++ b/src/material-experimental/mdc-list/action-list.ts @@ -14,7 +14,7 @@ import {MatListBase} from './list-base'; exportAs: 'matActionList', template: '', host: { - 'class': 'mat-mdc-action-list mat-mdc-list-base mdc-deprecated-list', + 'class': 'mat-mdc-action-list mat-mdc-list-base mdc--list', }, styleUrls: ['list.css'], encapsulation: ViewEncapsulation.None, diff --git a/src/material-experimental/mdc-list/list-base.ts b/src/material-experimental/mdc-list/list-base.ts index dc3564ca38fe..c36b585db02c 100644 --- a/src/material-experimental/mdc-list/list-base.ts +++ b/src/material-experimental/mdc-list/list-base.ts @@ -65,7 +65,6 @@ export abstract class MatListItemBase implements AfterContentInit, OnDestroy, Ri private _disableRipple: boolean = false; /** Whether the list-item is disabled. */ - @HostBinding('class.mdc-deprecated-list-item--disabled') @HostBinding('class.mdc-list-item--disabled') @HostBinding('attr.aria-disabled') @Input() @@ -155,11 +154,17 @@ export abstract class MatListItemBase implements AfterContentInit, OnDestroy, Ri this._subscriptions.add(this.lines.changes.pipe(startWith(this.lines)) .subscribe((lines: QueryList>) => { toggleClass(this._hostElement, 'mat-mdc-list-item-single-line', lines.length <= 1); + toggleClass(this._hostElement, 'mdc-list-item--with-one-line', lines.length <= 1); + lines.forEach((line: ElementRef, index: number) => { + toggleClass( + this._hostElement, 'mdc-list-item--with-two-lines', lines.length === 2); + toggleClass( + this._hostElement, 'mdc-list-item--with-three-lines', lines.length === 3); toggleClass(line.nativeElement, - 'mdc-deprecated-list-item__primary-text', index === 0 && lines.length > 1); + 'mdc-list-item__primary-text', index === 0 && lines.length > 1); toggleClass( - line.nativeElement, 'mdc-deprecated-list-item__secondary-text', index !== 0); + line.nativeElement, 'mdc-list-item__secondary-text', index !== 0); }); setLines(lines, this._elementRef, 'mat-mdc'); })); diff --git a/src/material-experimental/mdc-list/list-item.html b/src/material-experimental/mdc-list/list-item.html index ddcea90b6b1b..e00076915380 100644 --- a/src/material-experimental/mdc-list/list-item.html +++ b/src/material-experimental/mdc-list/list-item.html @@ -2,15 +2,15 @@ - + - + diff --git a/src/material-experimental/mdc-list/list-option.html b/src/material-experimental/mdc-list/list-option.html index 13acdd055c47..41ab9651188e 100644 --- a/src/material-experimental/mdc-list/list-option.html +++ b/src/material-experimental/mdc-list/list-option.html @@ -25,26 +25,26 @@ - + - + - + - + - + diff --git a/src/material-experimental/mdc-list/list-option.scss b/src/material-experimental/mdc-list/list-option.scss index 305cef366e29..c126fbbbc244 100644 --- a/src/material-experimental/mdc-list/list-option.scss +++ b/src/material-experimental/mdc-list/list-option.scss @@ -2,11 +2,16 @@ @use '@material/list' as mdc-list; @use '../mdc-helpers/mdc-helpers'; @use '../../cdk/a11y'; +@use './list-option-trailing-avatar-compat'; // The MDC-based list-option uses the MDC checkbox for the selection indicators. // We need to ensure that the checkbox styles are included for the list-option. @include mdc-checkbox.without-ripple($query: mdc-helpers.$mat-base-styles-query); +// For compatibility with the non-MDC list, we support avatars that are shown at the end +// of the list option. We create a class similar to MDC's `--trailing-icon` one. +@include list-option-trailing-avatar-compat.core-styles($query: mdc-helpers.$mat-base-styles-query); + // 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 diff --git a/src/material-experimental/mdc-list/list-option.ts b/src/material-experimental/mdc-list/list-option.ts index 5a9af758fca0..ba8d91b4aa68 100644 --- a/src/material-experimental/mdc-list/list-option.ts +++ b/src/material-experimental/mdc-list/list-option.ts @@ -62,12 +62,21 @@ export interface SelectionList extends MatListBase { exportAs: 'matListOption', styleUrls: ['list-option.css'], host: { - 'class': 'mat-mdc-list-item mat-mdc-list-option mdc-deprecated-list-item', + 'class': 'mat-mdc-list-item mat-mdc-list-option mdc-list-item', 'role': 'option', // 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-deprecated-list-item--selected]': 'selected && !_selectionList.multiple', - '[class.mat-mdc-list-item-with-avatar]': '_hasIconOrAvatar()', + '[class.mdc-list-item--selected]': 'selected && !_selectionList.multiple', + // Based on the checkbox 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. + '[class.mdc-list-item--with-leading-checkbox]': '_hasCheckboxAt("before")', + '[class.mdc-list-item--with-trailing-checkbox]': '_hasCheckboxAt("after")', '[class.mat-accent]': 'color !== "primary" && color !== "warn"', '[class.mat-warn]': 'color === "warn"', '(blur)': '_handleBlur()', @@ -188,14 +197,22 @@ export class MatListOption extends MatListItemBase implements ListOption, OnInit this._hostElement.focus(); } - /** Whether the checkbox should be shown at the given position. */ - _shouldShowCheckboxAt(position: MatListOptionCheckboxPosition): boolean { + /** Whether a checkbox is shown at the given position. */ + _hasCheckboxAt(position: MatListOptionCheckboxPosition): boolean { return this._selectionList.multiple && this._getCheckboxPosition() === position; } - /** Whether icons and avatars should be shown at the given position. */ - _shouldShowIconsAndAvatarsAt(position: 'before'|'after'): boolean { - return this._getCheckboxPosition() !== position && this._hasIconOrAvatar(); + /** Whether icons or avatars are shown at the given position. */ + _hasIconsOrAvatarsAt(position: 'before'|'after'): boolean { + return this._hasProjected('icons', position) || this._hasProjected('avatars', position); + } + + /** 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 + // avatars can be shown at the position. + return this._getCheckboxPosition() !== position && + (type === 'avatars' ? this._avatars.length !== 0 : this._icons.length !== 0); } _handleBlur() { diff --git a/src/material-experimental/mdc-list/list-styling.ts b/src/material-experimental/mdc-list/list-styling.ts index 654f1ad2712e..835098430795 100644 --- a/src/material-experimental/mdc-list/list-styling.ts +++ b/src/material-experimental/mdc-list/list-styling.ts @@ -10,17 +10,17 @@ import {Directive, Inject, Optional} from '@angular/core'; import {LIST_OPTION, ListOption} from './list-option-types'; /** - * MDC uses the very intuitively named classes `.mdc-deprecated-list-item__graphic` and - * `.mat-list-item__meta` 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 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 + * correct MDC class to position the icon/avatar on the opposite side. * @docs-private */ @Directive({ selector: '[mat-list-avatar], [matListAvatar], [mat-list-icon], [matListIcon]', host: { - '[class.mdc-deprecated-list-item__graphic]': '_isAlignedAtStart()', - '[class.mdc-deprecated-list-item__meta]': '!_isAlignedAtStart()', + '[class.mdc-list-item__start]': '_isAlignedAtStart()', + '[class.mdc-list-item__end]': '!_isAlignedAtStart()', } }) export class MatListGraphicAlignmentStyler { @@ -62,6 +62,6 @@ export class MatListIconCssMatStyler {} selector: '[mat-subheader], [matSubheader]', // TODO(mmalerba): MDC's subheader font looks identical to the list item font, figure out why and // make a change in one of the repos to visually distinguish. - host: {'class': 'mat-mdc-subheader mdc-deprecated-list-group__subheader'} + host: {'class': 'mat-mdc-subheader mdc-list-group__subheader'} }) export class MatListSubheaderCssMatStyler {} diff --git a/src/material-experimental/mdc-list/list.scss b/src/material-experimental/mdc-list/list.scss index 116807d9a15c..e51c7f214739 100644 --- a/src/material-experimental/mdc-list/list.scss +++ b/src/material-experimental/mdc-list/list.scss @@ -1,9 +1,8 @@ -@use '@material/list' as mdc-list; +@use '@material/list/evolution-mixins' as mdc-list; @use '../mdc-helpers/mdc-helpers'; @use '../../material/core/style/layout-common'; -@use '../../cdk/a11y'; -@include mdc-list.deprecated-without-ripple($query: mdc-helpers.$mat-base-styles-query); +@include mdc-list.without-ripple($query: mdc-helpers.$mat-base-styles-query); // MDC expects the list element to be a `
    `, since we use `` instead we need to // explicitly set `display: block` @@ -11,72 +10,6 @@ display: block; } -// .mdc-deprecated-list-item__primary-text adds its own margin settings, so only reset if it doesn't -// have that class -.mat-mdc-list-base .mdc-deprecated-list-item__text > :not(.mdc-deprecated-list-item__primary-text), -.mat-mdc-list-base .mdc-deprecated-list-item__text > :not(.mdc-deprecated-list-item__primary-text) { - margin: 0; - - // Fixes the gap between the 2nd & 3rd lines. - &.mdc-deprecated-list-item__secondary-text { - margin-top: -3px; - } -} - - -// MDC does have 2-line support, but it's a per-list setting, whereas ours applies to individual -// items. Therefore, we need to add our own styles. -.mat-mdc-2-line { - height: 72px; - - .mdc-deprecated-list-item__text { - align-self: flex-start; - } -} - -// MDC does not support more than 2 lines, so we need to add our own styles. -.mat-mdc-3-line { - height: 88px; - - .mdc-deprecated-list-item__text { - align-self: flex-start; - } -} - -// MDC supports avatars, but it's a per-list setting, whereas ours applies to individual -// items. Therefore, we need to add our own styles. -.mat-mdc-list-avatar { - // Styles here come from `mdc-list.$graphic-size_`: - // https://github.com/material-components/material-components-web/blob/3ca8c4c45a3d2a654ef3cb8fc7525bcde37badf0/packages/mdc-list/_mixins.scss#L538 - $size: 40px; - $margin-value: 72px - mdc-list.$deprecated-side-padding - $size; - - width: $size; - height: $size; - border-radius: 50%; - - // Avatars that come before the text have the .mdc-deprecated-list-item__graphic class. - // MDC's .mdc-deprecated-list--avatar-list class would normally apply overrides to set the - // appropriate margins for avatar images, but since ours is a per-list-item setting we need to add - // similar styles ourselves. - &.mdc-deprecated-list-item__graphic { - margin-left: 0; - margin-right: $margin-value; - - [dir='rtl'] & { - margin-left: $margin-value; - margin-right: 0; - } - } -} - -.mat-mdc-list-avatar { - // MDC's styles don't specify this, but they probably should. It gives a nicer experience when the - // image is not 1:1 aspect ratio. - // See https://github.com/material-components/material-components-web/issues/5897 - object-fit: cover; -} - // MDC expects that the list items are always `
  • `, since we actually use `