Skip to content

Commit 3a29d67

Browse files
crisbetokara
authored andcommitted
feat(select): allow setting the theme color (#3928)
Fixes #3923.
1 parent 94a2855 commit 3a29d67

File tree

8 files changed

+167
-57
lines changed

8 files changed

+167
-57
lines changed

src/demo-app/select/select-demo.html

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<md-card>
55
<md-card-subtitle>ngModel</md-card-subtitle>
66

7-
<md-select placeholder="Drink" [(ngModel)]="currentDrink" [required]="drinksRequired" [disabled]="drinksDisabled"
7+
<md-select placeholder="Drink" [color]="drinksTheme" [(ngModel)]="currentDrink" [required]="drinksRequired" [disabled]="drinksDisabled"
88
[floatPlaceholder]="floatPlaceholder" #drinkControl="ngModel">
99
<md-option *ngFor="let drink of drinks" [value]="drink.value" [disabled]="drink.disabled">
1010
{{ drink.viewValue }}
@@ -22,6 +22,12 @@
2222
<option value="never">Never</option>
2323
</select>
2424
</p>
25+
<p>
26+
<label for="drinks-theme">Theme:</label>
27+
<select [(ngModel)]="drinksTheme" id="drinks-theme">
28+
<option *ngFor="let theme of availableThemes" [value]="theme.value">{{ theme.name }}</option>
29+
</select>
30+
</p>
2531

2632
<button md-button (click)="currentDrink='water-2'">SET VALUE</button>
2733
<button md-button (click)="drinksRequired=!drinksRequired">TOGGLE REQUIRED</button>
@@ -33,7 +39,7 @@
3339
<md-card-subtitle>Multiple selection</md-card-subtitle>
3440

3541
<md-card-content>
36-
<md-select multiple placeholder="Pokemon" [(ngModel)]="currentPokemon"
42+
<md-select multiple [color]="pokemonTheme" placeholder="Pokemon" [(ngModel)]="currentPokemon"
3743
[required]="pokemonRequired" [disabled]="pokemonDisabled" #pokemonControl="ngModel">
3844
<md-option *ngFor="let creature of pokemon" [value]="creature.value">
3945
{{ creature.viewValue }}
@@ -43,6 +49,12 @@
4349
<p> Touched: {{ pokemonControl.touched }} </p>
4450
<p> Dirty: {{ pokemonControl.dirty }} </p>
4551
<p> Status: {{ pokemonControl.control?.status }} </p>
52+
<p>
53+
<label for="pokemon-theme">Theme:</label>
54+
<select [(ngModel)]="pokemonTheme" id="pokemon-theme">
55+
<option *ngFor="let theme of availableThemes" [value]="theme.value">{{ theme.name }}</option>
56+
</select>
57+
</p>
4658
<button md-button (click)="setPokemonValue()">SET VALUE</button>
4759
<button md-button (click)="pokemonRequired=!pokemonRequired">TOGGLE REQUIRED</button>
4860
<button md-button (click)="pokemonDisabled=!pokemonDisabled">TOGGLE DISABLED</button>

src/demo-app/select/select-demo.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ export class SelectDemo {
1919
latestChangeEvent: MdSelectChange;
2020
floatPlaceholder: string = 'auto';
2121
foodControl = new FormControl('pizza-1');
22+
drinksTheme = 'primary';
23+
pokemonTheme = 'primary';
2224

2325
foods = [
2426
{value: 'steak-0', viewValue: 'Steak'},
@@ -48,6 +50,12 @@ export class SelectDemo {
4850
{value: 'psyduck-6', viewValue: 'Psyduck'},
4951
];
5052

53+
availableThemes = [
54+
{value: 'primary', name: 'Primary' },
55+
{value: 'accent', name: 'Accent' },
56+
{value: 'warn', name: 'Warn' }
57+
];
58+
5159
toggleDisabled() {
5260
this.foodControl.enabled ? this.foodControl.disable() : this.foodControl.enable();
5361
}

src/lib/core/option/_option-theme.scss

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,29 @@
55
$foreground: map-get($theme, foreground);
66
$background: map-get($theme, background);
77
$primary: map-get($theme, primary);
8+
$accent: map-get($theme, accent);
9+
$warn: map-get($theme, warn);
810

911
.mat-option {
1012
&:hover:not(.mat-option-disabled), &:focus:not(.mat-option-disabled) {
1113
background: mat-color($background, hover);
1214
}
1315

14-
&.mat-selected {
16+
&.mat-selected.mat-primary, .mat-primary &.mat-selected {
1517
color: mat-color($primary);
18+
}
19+
20+
&.mat-selected.mat-accent, .mat-accent &.mat-selected {
21+
color: mat-color($accent);
22+
}
1623

17-
// In multiple mode there is a checkbox to show that the option is selected.
18-
&:not(.mat-option-multiple) {
19-
background: mat-color($background, hover);
20-
}
24+
&.mat-selected.mat-warn, .mat-warn &.mat-selected {
25+
color: mat-color($warn);
26+
}
27+
28+
// In multiple mode there is a checkbox to show that the option is selected.
29+
&.mat-selected:not(.mat-option-multiple) {
30+
background: mat-color($background, hover);
2131
}
2232

2333
&.mat-active {
@@ -28,6 +38,5 @@
2838
&.mat-option-disabled {
2939
color: mat-color($foreground, hint-text);
3040
}
31-
3241
}
3342
}

src/lib/core/selection/pseudo-checkbox/_pseudo-checkbox-theme.scss

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
@import '../../theming/theming';
22

3+
@mixin _mat-pseudo-checkbox-inner-content-theme($theme, $pallete-name) {
4+
$pallete: map-get($theme, $pallete-name);
5+
$color: mat-color($pallete, 500);
6+
7+
.mat-pseudo-checkbox-checked.mat-#{$pallete-name},
8+
.mat-pseudo-checkbox-indeterminate.mat-#{$pallete-name},
9+
.mat-#{$pallete-name} .mat-pseudo-checkbox-checked,
10+
.mat-#{$pallete-name} .mat-pseudo-checkbox-indeterminate {
11+
background: $color;
12+
}
13+
}
314

415
@mixin mat-pseudo-checkbox-theme($theme) {
516
$is-dark-theme: map-get($theme, is-dark);
@@ -14,6 +25,7 @@
1425
$white-30pct-opacity-on-dark: #686868;
1526
$black-26pct-opacity-on-light: #b0b0b0;
1627
$disabled-color: if($is-dark-theme, $white-30pct-opacity-on-dark, $black-26pct-opacity-on-light);
28+
$colored-box-selector: '.mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate';
1729

1830
.mat-pseudo-checkbox {
1931
color: mat-color(map-get($theme, foreground), secondary-text);
@@ -23,19 +35,11 @@
2335
}
2436
}
2537

26-
.mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate {
27-
&.mat-primary {
28-
background: mat-color($primary, 500);
29-
}
30-
31-
&.mat-accent {
32-
background: mat-color($accent, 500);
33-
}
34-
35-
&.mat-warn {
36-
background: mat-color($warn, 500);
37-
}
38+
@include _mat-pseudo-checkbox-inner-content-theme($theme, primary);
39+
@include _mat-pseudo-checkbox-inner-content-theme($theme, accent);
40+
@include _mat-pseudo-checkbox-inner-content-theme($theme, warn);
3841

42+
.mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate {
3943
&.mat-pseudo-checkbox-disabled {
4044
background: $disabled-color;
4145
}

src/lib/select/_select-theme.scss

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,33 @@
11
@import '../core/theming/palette';
22
@import '../core/theming/theming';
33

4+
@mixin _mat-select-inner-content-theme($palette) {
5+
$color: mat-color($palette);
6+
7+
.mat-select-trigger, .mat-select-arrow {
8+
color: $color;
9+
}
10+
11+
.mat-select-underline {
12+
background-color: $color;
13+
}
14+
}
15+
416
@mixin mat-select-theme($theme) {
517
$foreground: map-get($theme, foreground);
618
$background: map-get($theme, background);
719
$primary: map-get($theme, primary);
20+
$accent: map-get($theme, accent);
821
$warn: map-get($theme, warn);
922

10-
.mat-select-trigger {
11-
color: mat-color($foreground, hint-text);
12-
13-
.mat-select:focus:not(.mat-select-disabled) & {
14-
color: mat-color($primary);
15-
}
16-
17-
.mat-select:not(:focus).ng-invalid.ng-touched:not(.mat-select-disabled) & {
18-
color: mat-color($warn);
19-
}
20-
}
21-
2223
.mat-select-underline {
2324
background-color: mat-color($foreground, divider);
24-
25-
.mat-select:focus:not(.mat-select-disabled) & {
26-
background-color: mat-color($primary);
27-
}
28-
29-
.mat-select:not(:focus).ng-invalid.ng-touched:not(.mat-select-disabled) & {
30-
background-color: mat-color($warn);
31-
}
3225
}
3326

34-
.mat-select-arrow {
27+
.mat-select-disabled .mat-select-value,
28+
.mat-select-arrow,
29+
.mat-select-trigger {
3530
color: mat-color($foreground, hint-text);
36-
37-
.mat-select:focus:not(.mat-select-disabled) & {
38-
color: mat-color($primary);
39-
}
40-
41-
.mat-select:not(:focus).ng-invalid.ng-touched:not(.mat-select-disabled) & {
42-
color: mat-color($warn);
43-
}
4431
}
4532

4633
.mat-select-content, .mat-select-panel-done-animating {
@@ -49,9 +36,20 @@
4936

5037
.mat-select-value {
5138
color: mat-color($foreground, text);
39+
}
5240

53-
.mat-select-disabled & {
54-
color: mat-color($foreground, hint-text);
41+
.mat-select:focus:not(.mat-select-disabled) {
42+
&.mat-primary {
43+
@include _mat-select-inner-content-theme($primary);
5544
}
45+
46+
&.mat-accent {
47+
@include _mat-select-inner-content-theme($accent);
48+
}
49+
}
50+
51+
.mat-select:focus:not(.mat-select-disabled).mat-warn,
52+
.mat-select:not(:focus).ng-invalid.ng-touched:not(.mat-select-disabled) {
53+
@include _mat-select-inner-content-theme($warn);
5654
}
5755
}

src/lib/select/select.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
[offsetY]="_offsetY" [offsetX]="_offsetX" (attach)="_setScrollTop()" (detach)="close()">
1919
<div class="mat-select-panel" [@transformPanel]="'showing'" (@transformPanel.done)="_onPanelDone()"
2020
(keydown)="_keyManager.onKeydown($event)" [style.transformOrigin]="_transformOrigin"
21-
[class.mat-select-panel-done-animating]="_panelDoneAnimating">
21+
[class.mat-select-panel-done-animating]="_panelDoneAnimating" [ngClass]="'mat-' + color">
2222
<div class="mat-select-content" [@fadeInContent]="'showing'" (@fadeInContent.done)="_onFadeInDone()">
2323
<ng-content></ng-content>
2424
</div>

src/lib/select/select.spec.ts

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ describe('MdSelect', () => {
5050
SelectWithPlainTabindex,
5151
SelectEarlyAccessSibling,
5252
BasicSelectInitiallyHidden,
53-
BasicSelectNoPlaceholder
53+
BasicSelectNoPlaceholder,
54+
BasicSelectWithTheming
5455
],
5556
providers: [
5657
{provide: OverlayContainer, useFactory: () => {
@@ -1709,6 +1710,55 @@ describe('MdSelect', () => {
17091710

17101711
});
17111712

1713+
describe('theming', () => {
1714+
let fixture: ComponentFixture<BasicSelectWithTheming>;
1715+
let testInstance: BasicSelectWithTheming;
1716+
let selectElement: HTMLElement;
1717+
1718+
beforeEach(async(() => {
1719+
fixture = TestBed.createComponent(BasicSelectWithTheming);
1720+
testInstance = fixture.componentInstance;
1721+
fixture.detectChanges();
1722+
1723+
selectElement = fixture.debugElement.query(By.css('.mat-select')).nativeElement;
1724+
}));
1725+
1726+
it('should default to the primary theme', () => {
1727+
expect(fixture.componentInstance.select.color).toBe('primary');
1728+
expect(selectElement.classList).toContain('mat-primary');
1729+
});
1730+
1731+
it('should be able to override the theme', () => {
1732+
fixture.componentInstance.theme = 'accent';
1733+
fixture.detectChanges();
1734+
1735+
expect(fixture.componentInstance.select.color).toBe('accent');
1736+
expect(selectElement.classList).toContain('mat-accent');
1737+
expect(selectElement.classList).not.toContain('mat-primary');
1738+
});
1739+
1740+
it('should not be able to set a blank theme', () => {
1741+
fixture.componentInstance.theme = '';
1742+
fixture.detectChanges();
1743+
1744+
expect(fixture.componentInstance.select.color).toBe('primary');
1745+
expect(selectElement.classList).toContain('mat-primary');
1746+
});
1747+
1748+
it('should pass the theme to the panel', () => {
1749+
fixture.componentInstance.theme = 'warn';
1750+
fixture.debugElement.query(By.css('.mat-select-trigger')).nativeElement.click();
1751+
fixture.detectChanges();
1752+
1753+
const panel = overlayContainerElement.querySelector('.mat-select-panel');
1754+
1755+
expect(fixture.componentInstance.select.color).toBe('warn');
1756+
expect(selectElement.classList).toContain('mat-warn');
1757+
expect(panel.classList).toContain('mat-warn');
1758+
});
1759+
1760+
});
1761+
17121762
});
17131763

17141764

@@ -2040,6 +2090,20 @@ class BasicSelectInitiallyHidden {
20402090
})
20412091
class BasicSelectNoPlaceholder { }
20422092

2093+
@Component({
2094+
selector: 'basic-select-with-theming',
2095+
template: `
2096+
<md-select placeholder="Food" [color]="theme">
2097+
<md-option value="steak-0">Steak</md-option>
2098+
<md-option value="pizza-1">Pizza</md-option>
2099+
</md-select>
2100+
`
2101+
})
2102+
class BasicSelectWithTheming {
2103+
@ViewChild(MdSelect) select: MdSelect;
2104+
theme: string;
2105+
}
2106+
20432107
class FakeViewportRuler {
20442108
getViewportRect() {
20452109
return {

0 commit comments

Comments
 (0)