Skip to content

feat(material-experimental/mdc-list): implement selection list #20279

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@
/src/material-experimental/mdc-form-field/** @devversion @mmalerba
/src/material-experimental/mdc-helpers/** @mmalerba
/src/material-experimental/mdc-input/** @devversion @mmalerba
/src/material-experimental/mdc-list/** @mmalerba
/src/material-experimental/mdc-list/** @mmalerba @devversion
/src/material-experimental/mdc-menu/** @crisbeto
/src/material-experimental/mdc-select/** @crisbeto
/src/material-experimental/mdc-progress-spinner/** @andrewseguin
Expand Down
21 changes: 20 additions & 1 deletion src/dev-app/list/list-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ <h2>Selection list</h2>

<mat-selection-list #groceries [ngModel]="selectedOptions"
(ngModelChange)="onSelectedOptionsChange($event)"
(change)="changeEventCount = changeEventCount + 1"
(selectionChange)="changeEventCount = changeEventCount + 1"
[disabled]="selectionListDisabled"
[disableRipple]="selectionListRippleDisabled"
color="primary">
Expand Down Expand Up @@ -180,4 +180,23 @@ <h2>Single Selection list</h2>

<p>Selected: {{favoriteOptions | json}}</p>
</div>

<div>
<h2>Line alignment</h2>

<mat-list>
<mat-list-item *ngFor="let link of links">
<span mat-line>{{ link.name }}</span>
<span>Not in an <i>matLine</i></span>
</mat-list-item>
</mat-list>

<mat-selection-list>
<mat-list-option value="first">First</mat-list-option>
<mat-list-option value="second">
<span matLine>Second</span>
<span>Not in an <i>matLine</i></span>
</mat-list-option>
</mat-selection-list>
</div>
</div>
1 change: 0 additions & 1 deletion src/dev-app/mdc-list/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ ng_module(
],
deps = [
"//src/material-experimental/mdc-button",
"//src/material-experimental/mdc-checkbox",
"//src/material-experimental/mdc-list",
"//src/material/icon",
"@npm//@angular/router",
Expand Down
2 changes: 0 additions & 2 deletions src/dev-app/mdc-list/mdc-list-demo-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MatButtonModule} from '@angular/material-experimental/mdc-button';
import {MatCheckboxModule} from '@angular/material-experimental/mdc-checkbox';
import {MatListModule} from '@angular/material-experimental/mdc-list';
import {MatIconModule} from '@angular/material/icon';
import {RouterModule} from '@angular/router';
Expand All @@ -21,7 +20,6 @@ import {MdcListDemo} from './mdc-list-demo';
CommonModule,
FormsModule,
MatButtonModule,
MatCheckboxModule,
MatIconModule,
MatListModule,
RouterModule.forChild([{path: '', component: MdcListDemo}]),
Expand Down
33 changes: 27 additions & 6 deletions src/dev-app/mdc-list/mdc-list-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ <h2>Selection list</h2>

<mat-selection-list #groceries [ngModel]="selectedOptions"
(ngModelChange)="onSelectedOptionsChange($event)"
(change)="changeEventCount = changeEventCount + 1"
(selectionChange)="changeEventCount = changeEventCount + 1"
[disabled]="selectionListDisabled"
[disableRipple]="selectionListRippleDisabled"
color="primary">
Expand Down Expand Up @@ -148,14 +148,16 @@ <h2>Selection list</h2>
<p>Change Event Count {{changeEventCount}}</p>
<p>Model Change Event Count {{modelChangeEventCount}}</p>
<p>
<mat-checkbox [(ngModel)]="selectionListDisabled">
Disable Selection List
</mat-checkbox>
<label>
Disable selection list
<input type="checkbox" [(ngModel)]="selectionListDisabled">
</label>
</p>
<p>
<mat-checkbox [(ngModel)]="selectionListRippleDisabled">
<label>
Disable Selection List ripples
</mat-checkbox>
<input type="checkbox" [(ngModel)]="selectionListRippleDisabled">
</label>
</p>
<p>
<button mat-raised-button (click)="groceries.selectAll()">Select all</button>
Expand All @@ -180,4 +182,23 @@ <h2>Single Selection list</h2>

<p>Selected: {{favoriteOptions | json}}</p>
</div>

<div>
<h2>Line alignment</h2>

<mat-list>
<mat-list-item *ngFor="let link of links">
<span mat-line>{{ link.name }}</span>
<span>Not in an <i>matLine</i></span>
</mat-list-item>
</mat-list>

<mat-selection-list>
<mat-list-option value="first">First</mat-list-option>
<mat-list-option value="second">
<span matLine>Second</span>
<span>Not in an <i>matLine</i></span>
</mat-list-option>
</mat-selection-list>
</div>
</div>
32 changes: 17 additions & 15 deletions src/material-experimental/mdc-checkbox/_checkbox-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,20 @@
@import '@material/theme/functions.import';
@import '../mdc-helpers/mdc-helpers';

// Mixin that includes the checkbox theme styles with a given palette.
// By default, the MDC checkbox always uses the `secondary` palette.
@mixin _mdc-checkbox-styles-with-color($color) {
$orig-mdc-checkbox-mark-color: $mdc-checkbox-mark-color;
$mdc-checkbox-mark-color: mdc-theme-prop-value(on-#{$color}) !global;
$orig-mdc-checkbox-baseline-theme-color: $mdc-checkbox-baseline-theme-color;
$mdc-checkbox-baseline-theme-color: $color !global;

@include mdc-checkbox-without-ripple($query: $mat-theme-styles-query);

$mdc-checkbox-mark-color: $orig-mdc-checkbox-mark-color !global;
$mdc-checkbox-baseline-theme-color: $orig-mdc-checkbox-baseline-theme-color !global;
}

@mixin mat-mdc-checkbox-color($config-or-theme) {
$config: mat-get-color-config($config-or-theme);
$primary: mat-color(map-get($config, primary));
Expand All @@ -13,18 +27,14 @@

// Save original values of MDC global variables. We need to save these so we can restore the
// variables to their original values and prevent unintended side effects from using this mixin.
$orig-mdc-checkbox-mark-color: $mdc-checkbox-mark-color;
$orig-mdc-checkbox-baseline-theme-color: $mdc-checkbox-baseline-theme-color;
$orig-mdc-checkbox-border-color: $mdc-checkbox-border-color;
$orig-mdc-checkbox-disabled-color: $mdc-checkbox-disabled-color;

@include mat-using-mdc-theme($config) {
$mdc-checkbox-mark-color: mdc-theme-prop-value(on-primary) !global;
$mdc-checkbox-baseline-theme-color: primary !global;
$mdc-checkbox-border-color: rgba(mdc-theme-prop-value(on-surface), 0.54) !global;
$mdc-checkbox-disabled-color: rgba(mdc-theme-prop-value(on-surface), 0.26) !global;

@include mdc-checkbox-without-ripple($query: $mat-theme-styles-query);
@include _mdc-checkbox-styles-with-color(primary);
@include mdc-form-field-core-styles($query: $mat-theme-styles-query);

// MDC's checkbox doesn't support a `color` property. We add support for it by adding a CSS
Expand All @@ -41,21 +51,15 @@
}

&.mat-accent {
$mdc-checkbox-mark-color: mdc-theme-prop-value(on-secondary) !global;
$mdc-checkbox-baseline-theme-color: secondary !global;

@include mdc-checkbox-without-ripple($query: $mat-theme-styles-query);
@include _mdc-checkbox-styles-with-color(secondary);

.mdc-checkbox--selected ~ .mat-mdc-checkbox-ripple .mat-ripple-element {
background: $accent;
}
}

&.mat-warn {
$mdc-checkbox-mark-color: mdc-theme-prop-value(on-error) !global;
$mdc-checkbox-baseline-theme-color: error !global;

@include mdc-checkbox-without-ripple($query: $mat-theme-styles-query);
@include _mdc-checkbox-styles-with-color(error);

.mdc-checkbox--selected ~ .mat-mdc-checkbox-ripple .mat-ripple-element {
background: $warn;
Expand All @@ -65,8 +69,6 @@
}

// Restore original values of MDC global variables.
$mdc-checkbox-mark-color: $orig-mdc-checkbox-mark-color !global;
$mdc-checkbox-baseline-theme-color: $orig-mdc-checkbox-baseline-theme-color !global;
$mdc-checkbox-border-color: $orig-mdc-checkbox-border-color !global;
$mdc-checkbox-disabled-color: $orig-mdc-checkbox-disabled-color !global;
}
Expand Down
22 changes: 21 additions & 1 deletion src/material-experimental/mdc-list/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ ng_module(
"**/*.spec.ts",
],
),
assets = [":list_scss"] + glob(["**/*.html"]),
assets = [
":list_scss",
":list_option_scss",
] + glob(["**/*.html"]),
module_name = "@angular/material-experimental/mdc-list",
deps = [
"//src/cdk/collections",
Expand All @@ -34,6 +37,7 @@ sass_library(
name = "mdc_list_scss_lib",
srcs = glob(["**/_*.scss"]),
deps = [
"//src/material-experimental/mdc-checkbox:mdc_checkbox_scss_lib",
"//src/material-experimental/mdc-helpers:mdc_helpers_scss_lib",
"//src/material-experimental/mdc-helpers:mdc_scss_deps_lib",
],
Expand All @@ -51,6 +55,18 @@ sass_binary(
],
)

sass_binary(
name = "list_option_scss",
src = "list-option.scss",
include_paths = [
"external/npm/node_modules",
],
deps = [
"//src/material-experimental/mdc-helpers:mdc_helpers_scss_lib",
"//src/material-experimental/mdc-helpers:mdc_scss_deps_lib",
],
)

ng_test_library(
name = "list_tests_lib",
srcs = glob(
Expand All @@ -59,9 +75,13 @@ ng_test_library(
),
deps = [
":mdc-list",
"//src/cdk/keycodes",
"//src/cdk/testing/private",
"//src/cdk/testing/testbed",
"//src/material/core",
"@npm//@angular/forms",
"@npm//@angular/platform-browser",
"@npm//@material/list",
],
)

Expand Down
33 changes: 33 additions & 0 deletions src/material-experimental/mdc-list/_interactive-list-theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@import '@material/ripple/variables.import';
@import '../mdc-helpers/mdc-helpers';

// Mixin that provides colors for the various states of an interactive list-item. MDC
// has integrated styles for these states but relies on their complex ripples for it.
@mixin _mat-mdc-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);

.mat-mdc-list-item-interactive {
&::before {
background: if($is-dark-theme, white, black);
}

&.mdc-list-item--selected::before {
background: mat-color(map_get($config, primary));
opacity: map-get($state-opacities, selected);
}

&:focus::before {
opacity: map-get($state-opacities, 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-list-item--disabled) {
&:hover::before {
opacity: map-get($state-opacities, hover);
}
}
}
41 changes: 41 additions & 0 deletions src/material-experimental/mdc-list/_list-option-theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
@import '@material/theme/mixins.import';
@import '@material/list/mixins.import';
@import '@material/checkbox/mixins.import';

@import '../mdc-checkbox/checkbox-theme';

// 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 _mat-mdc-list-option-color-override($color) {
& .mdc-list-item__meta, & .mdc-list-item__graphic {
@include _mdc-checkbox-styles-with-color($color);
}

&.mdc-list-item--selected {
@include mdc-list-item-primary-text-ink-color($color);
@include mdc-list-item-graphic-ink-color($color);

&::before {
@include mdc-theme-prop(background, $color);
}
}
}

@mixin _mat-mdc-list-option-density-styles($density-scale) {
.mat-mdc-list-option {
.mdc-list-item__meta, .mdc-list-item__graphic {
.mdc-checkbox {
@include mdc-checkbox-density($density-scale, $query: $mat-base-styles-query);
}
}
}
}

@mixin _mat-mdc-list-option-typography-styles() {
.mat-mdc-list-option {
.mdc-list-item__meta, .mdc-list-item__graphic {
@include mdc-checkbox-without-ripple($query: $mat-typography-styles-query);
}
}
}
36 changes: 19 additions & 17 deletions src/material-experimental/mdc-list/_list-theme.scss
Original file line number Diff line number Diff line change
@@ -1,34 +1,33 @@
@import '@material/density/functions.import';
@import '@material/list/variables.import';
@import '@material/list/mixins.import';
@import '@material/ripple/variables.import';

@import './interactive-list-theme';
@import './list-option-theme';
@import '../mdc-helpers/mdc-helpers';


// TODO: implement mat-list[dense] once density system is in master


@mixin mat-mdc-list-color($config-or-theme) {
$config: mat-get-color-config($config-or-theme);
$is-dark-theme: map-get($config, is-dark);
$state-opacities:
if($is-dark-theme, $mdc-ripple-light-ink-opacities, $mdc-ripple-dark-ink-opacities);

// MDC's state styles are tied in with their ripple. Since we don't use the MDC
// ripple, we need to add the hover, focus and selected states manually.
@include _mat-mdc-interactive-list-item-state-colors($config);

@include mat-using-mdc-theme($config) {
@include mdc-list-without-ripple($query: $mat-theme-styles-query);
}

// MDC's state styles are tied in with their ripple. Since we don't use the MDC ripple, we need to
// add the hover and focus states manually.
.mat-mdc-list-item-interactive {
&::before {
background: if($is-dark-theme, white, black);
.mat-mdc-list-option {
@include _mat-mdc-list-option-color-override(primary);
}

&:hover::before {
opacity: map-get($state-opacities, hover);
.mat-mdc-list-option.mat-accent {
@include _mat-mdc-list-option-color-override(secondary);
}

&:focus::before {
opacity: map-get($state-opacities, focus);
.mat-mdc-list-option.mat-warn {
@include _mat-mdc-list-option-color-override(error);
}
}
}
Expand All @@ -42,18 +41,21 @@
);

// MDC list provides a mixin called `mdc-list-single-line-density`, but we cannot use
// that mixin the generated generated density styles are scoped to `.mdc-list-item`, while
// that mixin, as the generated generated density styles are scoped to `.mdc-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-single-line-height($height);
}

@include _mat-mdc-list-option-density-styles($density-scale);
}

@mixin mat-mdc-list-typography($config-or-theme) {
$config: mat-get-typography-config($config-or-theme);
@include mat-using-mdc-typography($config) {
@include mdc-list-without-ripple($query: $mat-typography-styles-query);
@include _mat-mdc-list-option-typography-styles();
}
}

Expand Down
Loading