From dd239dd94df715daf4fa6d47b727012c3b8f4ba1 Mon Sep 17 00:00:00 2001 From: mmalerba Date: Thu, 12 Mar 2020 14:13:56 -0700 Subject: [PATCH] fix(material-experimental/mdc-list): fix styles for normal lists (#18632) * fix(material-experimental/mdc-list): fix styles for normal lists Fixes up various styles for the lists under the "normal lists" section of the demo. There are still some issues around the avatars and dividers on the last list * fix avatars and dividers * fix lint and api * address feedback --- .stylelintrc.json | 4 +- .../list-sections/list-sections-example.html | 12 +-- src/dev-app/list/list-demo.html | 42 +++++------ src/dev-app/mdc-list/mdc-list-demo.html | 40 +++++----- .../mdc-list/list-base.ts | 38 +++++++++- .../mdc-list/list-item.html | 2 + src/material-experimental/mdc-list/list.scss | 73 +++++++++++++++++++ src/material-experimental/mdc-list/list.ts | 29 ++++++-- src/material-experimental/mdc-list/module.ts | 3 + .../mdc-list/selection-list.ts | 21 +++++- src/material/core/line/line.ts | 13 ++-- tools/public_api_guard/material/core.d.ts | 2 +- 12 files changed, 216 insertions(+), 63 deletions(-) diff --git a/.stylelintrc.json b/.stylelintrc.json index a162e2394e36..cd68ab6a477d 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -87,7 +87,9 @@ "selector-max-id": 0, "no-missing-end-of-source-newline": true, "no-eol-whitespace": true, - "max-line-length": 100, + "max-line-length": [100, { + "ignorePattern": "/https?://.*/" + }], "linebreaks": "unix", "selector-class-pattern": ["^_?(mat-|cdk-|example-|demo-|ng-|mdc-|map-)", { "resolveNestedSelectors": true diff --git a/src/components-examples/material/list/list-sections/list-sections-example.html b/src/components-examples/material/list/list-sections/list-sections-example.html index ecb32bb2e8e6..935f0e77178a 100644 --- a/src/components-examples/material/list/list-sections/list-sections-example.html +++ b/src/components-examples/material/list/list-sections/list-sections-example.html @@ -1,15 +1,15 @@ -

Folders

+
Folders
folder -

{{folder.name}}

-

{{folder.updated | date}}

+
{{folder.name}}
+
{{folder.updated | date}}
-

Notes

+
Notes
note -

{{note.name}}

-

{{note.updated | date}}

+
{{note.name}}
+
{{note.updated | date}}
diff --git a/src/dev-app/list/list-demo.html b/src/dev-app/list/list-demo.html index 83918a690db0..b238517189eb 100644 --- a/src/dev-app/list/list-demo.html +++ b/src/dev-app/list/list-demo.html @@ -8,7 +8,7 @@

mat-list demo

Normal lists

-

Items

+
Items
{{item}} @@ -16,28 +16,28 @@

Items

-

{{contact.name}}

-

extra line

-

{{contact.headline}}

+
{{contact.name}}
+
extra line
+
{{contact.headline}}
-

Today

+
Today
Image of {{message.from}} -

{{message.from}}

-

+

{{message.from}}
+
{{message.subject}} -- {{message.message}} -

+
-

{{message.from}}

-

{{message.subject}}

-

{{message.message}}

+
{{message.from}}
+
{{message.subject}}
+
{{message.message}}
@@ -45,7 +45,7 @@

{{message.from}}

Dense lists

-

Items

+
Items
{{item}} @@ -53,18 +53,18 @@

Items

-

{{contact.name}}

-

{{contact.headline}}

+
{{contact.name}}
+
{{contact.headline}}
-

Today

+
Today
Image of {{message.from}} -

{{message.from}}

-

{{message.subject}}

-

{{message.message}}

+
{{message.from}}
+
{{message.subject}}
+
{{message.message}}
@@ -122,7 +122,7 @@

Selection list

[disabled]="selectionListDisabled" [disableRipple]="selectionListRippleDisabled" color="primary"> -

Groceries

+
Groceries
Bananas Oranges @@ -131,7 +131,7 @@

Groceries

-

Dogs

+
Dogs
@@ -170,7 +170,7 @@

Single Selection list

[(ngModel)]="favoriteOptions" [multiple]="false" color="primary"> -

Favorite Grocery

+
Favorite Grocery
Bananas Oranges diff --git a/src/dev-app/mdc-list/mdc-list-demo.html b/src/dev-app/mdc-list/mdc-list-demo.html index 80fe14661e23..83cbb5ed2020 100644 --- a/src/dev-app/mdc-list/mdc-list-demo.html +++ b/src/dev-app/mdc-list/mdc-list-demo.html @@ -8,7 +8,7 @@

mat-list demo

Normal lists

-

Items

+
Items
{{item}} @@ -16,28 +16,28 @@

Items

-

{{contact.name}}

-

extra line

-

{{contact.headline}}

+
{{contact.name}}
+
extra line
+
{{contact.headline}}
-

Today

+
Today
Image of {{message.from}} -

{{message.from}}

-

+

{{message.from}}
+
{{message.subject}} -- - {{message.message}} -

+ {{message.message}} +
-

{{message.from}}

-

{{message.subject}}

-

{{message.message}}

+
{{message.from}}
+
{{message.subject}}
+
{{message.message}}
@@ -45,7 +45,7 @@

{{message.from}}

Dense lists

-

Items

+
Items
{{item}} @@ -53,18 +53,18 @@

Items

-

{{contact.name}}

-

{{contact.headline}}

+
{{contact.name}}
+
{{contact.headline}}
-

Today

+
Today
Image of {{message.from}} -

{{message.from}}

-

{{message.subject}}

-

{{message.message}}

+
{{message.from}}
+
{{message.subject}}
+
{{message.message}}
@@ -90,7 +90,7 @@

Nav lists

folder {{ link.name }} - Description + Description diff --git a/src/material-experimental/mdc-list/list-base.ts b/src/material-experimental/mdc-list/list-base.ts index 1c42e8a22378..a233d777b733 100644 --- a/src/material-experimental/mdc-list/list-base.ts +++ b/src/material-experimental/mdc-list/list-base.ts @@ -6,6 +6,42 @@ * found in the LICENSE file at https://angular.io/license */ +import {AfterContentInit, ElementRef, NgZone, OnDestroy, QueryList} from '@angular/core'; +import {setLines} from '@angular/material/core'; +import {Subscription} from 'rxjs'; +import {startWith} from 'rxjs/operators'; + export class MatListBase {} -export class MatListItemBase {} +export class MatListItemBase implements AfterContentInit, OnDestroy { + lines: QueryList>; + + private _subscriptions = new Subscription(); + + constructor(protected _element: ElementRef, protected _ngZone: NgZone) {} + + ngAfterContentInit() { + this._monitorLines(); + } + + /** + * Subscribes to changes in `MatLine` content children and annotates them appropriately when they + * change. + */ + private _monitorLines() { + this._ngZone.runOutsideAngular(() => { + this._subscriptions.add(this.lines.changes.pipe(startWith(this.lines)) + .subscribe((lines: QueryList>) => { + lines.forEach((line: ElementRef, index: number) => { + line.nativeElement.classList.toggle('mdc-list-item__primary-text', index === 0); + line.nativeElement.classList.toggle('mdc-list-item__secondary-text', index !== 0); + }); + setLines(lines, this._element, 'mat-mdc'); + })); + }); + } + + ngOnDestroy() { + this._subscriptions.unsubscribe(); + } +} diff --git a/src/material-experimental/mdc-list/list-item.html b/src/material-experimental/mdc-list/list-item.html index 91b88fdf57fa..fbaeab2cecaa 100644 --- a/src/material-experimental/mdc-list/list-item.html +++ b/src/material-experimental/mdc-list/list-item.html @@ -1 +1,3 @@ + + diff --git a/src/material-experimental/mdc-list/list.scss b/src/material-experimental/mdc-list/list.scss index efba495ceb33..e08b039b73e7 100644 --- a/src/material-experimental/mdc-list/list.scss +++ b/src/material-experimental/mdc-list/list.scss @@ -1,4 +1,5 @@ @import '@material/list/mixins.import'; +@import '@material/list/variables.import'; @import '../mdc-helpers/mdc-helpers'; @include mdc-list-without-ripple($query: $mat-base-styles-query); @@ -8,3 +9,75 @@ .mat-mdc-list-base { display: block; } + +// .mdc-list-item__primary-text adds its own margin settings, so only reset if it doesn't have that +// class +.mat-mdc-list-base .mdc-list-item__text > :not(.mdc-list-item__primary-text), +.mat-mdc-list-base .mdc-list-item__text > :not(.mdc-list-item__primary-text) { + margin: 0; + + // Fixes the gap between the 2nd & 3rd lines. + &.mdc-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-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-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-side-padding - $size; + + margin-left: 0; + margin-right: $margin-value; + width: $size; + height: $size; + border-radius: 50%; + + // `.mdc-list-item` added for extra specificity to override MDC's built in styles. + [dir='rtl'] .mdc-list-item & { + margin-left: $margin-value; + margin-right: 0; + } +} + +// MDC doesn't have list dividers, so we use mat-divider and style appropriately. +.mat-mdc-list-item, +.mat-mdc-list-option { + .mat-divider-inset { + position: absolute; + left: 0; + right: 0; + bottom: 0; + } + + .mat-mdc-list-avatar ~ .mat-divider-inset { + margin-left: 72px; + + [dir='rtl'] & { + margin-right: 72px; + } + } +} diff --git a/src/material-experimental/mdc-list/list.ts b/src/material-experimental/mdc-list/list.ts index cc0d4c205cfb..343ca498420b 100644 --- a/src/material-experimental/mdc-list/list.ts +++ b/src/material-experimental/mdc-list/list.ts @@ -6,7 +6,17 @@ * found in the LICENSE file at https://angular.io/license */ -import {ChangeDetectionStrategy, Component, Directive, ViewEncapsulation} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ContentChildren, + Directive, + ElementRef, + NgZone, + QueryList, + ViewEncapsulation +} from '@angular/core'; +import {MatLine} from '@angular/material/core'; import {MatListBase, MatListItemBase} from './list-base'; /** @@ -15,7 +25,7 @@ import {MatListBase, MatListItemBase} from './list-base'; */ @Directive({ selector: '[mat-list-avatar], [matListAvatar]', - host: {'class': 'mat-mdc-list-avatar'} + host: {'class': 'mat-mdc-list-avatar mdc-list-item__graphic'} }) export class MatListAvatarCssMatStyler {} @@ -25,7 +35,7 @@ export class MatListAvatarCssMatStyler {} */ @Directive({ selector: '[mat-list-icon], [matListIcon]', - host: {'class': 'mat-mdc-list-icon'} + host: {'class': 'mat-mdc-list-icon mdc-list-item__graphic'} }) export class MatListIconCssMatStyler {} @@ -35,7 +45,9 @@ export class MatListIconCssMatStyler {} */ @Directive({ selector: '[mat-subheader], [matSubheader]', - host: {'class': 'mat-mdc-subheader'} + // 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-list-group__subheader'} }) export class MatListSubheaderCssMatStyler {} @@ -62,4 +74,11 @@ export class MatList extends MatListBase {} encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, }) -export class MatListItem extends MatListItemBase {} +export class MatListItem extends MatListItemBase { + @ContentChildren(MatLine, {read: ElementRef, descendants: true}) lines: + QueryList>; + + constructor(element: ElementRef, ngZone: NgZone) { + super(element, ngZone); + } +} diff --git a/src/material-experimental/mdc-list/module.ts b/src/material-experimental/mdc-list/module.ts index dd26e817da30..081a23ba2cf6 100644 --- a/src/material-experimental/mdc-list/module.ts +++ b/src/material-experimental/mdc-list/module.ts @@ -7,6 +7,7 @@ */ import {NgModule} from '@angular/core'; +import {MatLineModule} from '@angular/material/core'; import {MatDividerModule} from '@angular/material/divider'; import {MatActionList} from './action-list'; import { @@ -20,6 +21,7 @@ import {MatNavList} from './nav-list'; import {MatListOption, MatSelectionList} from './selection-list'; @NgModule({ + imports: [MatLineModule], exports: [ MatList, MatActionList, @@ -31,6 +33,7 @@ import {MatListOption, MatSelectionList} from './selection-list'; MatListIconCssMatStyler, MatListSubheaderCssMatStyler, MatDividerModule, + MatLineModule, ], declarations: [ MatList, diff --git a/src/material-experimental/mdc-list/selection-list.ts b/src/material-experimental/mdc-list/selection-list.ts index ea725da19ce2..f42aa9384420 100644 --- a/src/material-experimental/mdc-list/selection-list.ts +++ b/src/material-experimental/mdc-list/selection-list.ts @@ -6,8 +6,18 @@ * found in the LICENSE file at https://angular.io/license */ -import {ChangeDetectionStrategy, Component, forwardRef, ViewEncapsulation} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ContentChildren, + ElementRef, + forwardRef, + NgZone, + QueryList, + ViewEncapsulation +} from '@angular/core'; import {NG_VALUE_ACCESSOR} from '@angular/forms'; +import {MatLine} from '@angular/material/core'; import {MatListBase, MatListItemBase} from './list-base'; const MAT_SELECTION_LIST_VALUE_ACCESSOR: any = { @@ -49,4 +59,11 @@ export class MatSelectionList extends MatListBase {} encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, }) -export class MatListOption extends MatListItemBase {} +export class MatListOption extends MatListItemBase { + @ContentChildren(MatLine, {read: ElementRef, descendants: true}) lines: + QueryList>; + + constructor(element: ElementRef, ngZone: NgZone) { + super(element, ngZone); + } +} diff --git a/src/material/core/line/line.ts b/src/material/core/line/line.ts index 724a1dfe1226..33888dd858e2 100644 --- a/src/material/core/line/line.ts +++ b/src/material/core/line/line.ts @@ -31,18 +31,19 @@ export class MatLine {} * Helper that takes a query list of lines and sets the correct class on the host. * @docs-private */ -export function setLines(lines: QueryList, element: ElementRef) { +export function setLines(lines: QueryList, element: ElementRef, + prefix = 'mat') { // Note: doesn't need to unsubscribe, because `changes` // gets completed by Angular when the view is destroyed. lines.changes.pipe(startWith(lines)).subscribe(({length}) => { - setClass(element, 'mat-2-line', false); - setClass(element, 'mat-3-line', false); - setClass(element, 'mat-multi-line', false); + setClass(element, `${prefix}-2-line`, false); + setClass(element, `${prefix}-3-line`, false); + setClass(element, `${prefix}-multi-line`, false); if (length === 2 || length === 3) { - setClass(element, `mat-${length}-line`, true); + setClass(element, `${prefix}-${length}-line`, true); } else if (length > 3) { - setClass(element, `mat-multi-line`, true); + setClass(element, `${prefix}-multi-line`, true); } }); } diff --git a/tools/public_api_guard/material/core.d.ts b/tools/public_api_guard/material/core.d.ts index 28990691207f..61775aa88254 100644 --- a/tools/public_api_guard/material/core.d.ts +++ b/tools/public_api_guard/material/core.d.ts @@ -457,7 +457,7 @@ export declare type SanityChecks = boolean | GranularSanityChecks; export declare const JAN = 0, FEB = 1, MAR = 2, APR = 3, MAY = 4, JUN = 5, JUL = 6, AUG = 7, SEP = 8, OCT = 9, NOV = 10, DEC = 11; -export declare function setLines(lines: QueryList, element: ElementRef): void; +export declare function setLines(lines: QueryList, element: ElementRef, prefix?: string): void; export declare class ShowOnDirtyErrorStateMatcher implements ErrorStateMatcher { isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean;