Skip to content

feat(select): allow setting the theme color #3928

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 3 commits into from
Apr 21, 2017
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
16 changes: 14 additions & 2 deletions src/demo-app/select/select-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<md-card>
<md-card-subtitle>ngModel</md-card-subtitle>

<md-select placeholder="Drink" [(ngModel)]="currentDrink" [required]="drinksRequired" [disabled]="drinksDisabled"
<md-select placeholder="Drink" [color]="drinksTheme" [(ngModel)]="currentDrink" [required]="drinksRequired" [disabled]="drinksDisabled"
[floatPlaceholder]="floatPlaceholder" #drinkControl="ngModel">
<md-option *ngFor="let drink of drinks" [value]="drink.value" [disabled]="drink.disabled">
{{ drink.viewValue }}
Expand All @@ -22,6 +22,12 @@
<option value="never">Never</option>
</select>
</p>
<p>
<label for="drinks-theme">Theme:</label>
<select [(ngModel)]="drinksTheme" id="drinks-theme">
<option *ngFor="let theme of availableThemes" [value]="theme.value">{{ theme.name }}</option>
</select>
</p>

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

<md-card-content>
<md-select multiple placeholder="Pokemon" [(ngModel)]="currentPokemon"
<md-select multiple [color]="pokemonTheme" placeholder="Pokemon" [(ngModel)]="currentPokemon"
[required]="pokemonRequired" [disabled]="pokemonDisabled" #pokemonControl="ngModel">
<md-option *ngFor="let creature of pokemon" [value]="creature.value">
{{ creature.viewValue }}
Expand All @@ -43,6 +49,12 @@
<p> Touched: {{ pokemonControl.touched }} </p>
<p> Dirty: {{ pokemonControl.dirty }} </p>
<p> Status: {{ pokemonControl.control?.status }} </p>
<p>
<label for="pokemon-theme">Theme:</label>
<select [(ngModel)]="pokemonTheme" id="pokemon-theme">
<option *ngFor="let theme of availableThemes" [value]="theme.value">{{ theme.name }}</option>
</select>
</p>
<button md-button (click)="setPokemonValue()">SET VALUE</button>
<button md-button (click)="pokemonRequired=!pokemonRequired">TOGGLE REQUIRED</button>
<button md-button (click)="pokemonDisabled=!pokemonDisabled">TOGGLE DISABLED</button>
Expand Down
8 changes: 8 additions & 0 deletions src/demo-app/select/select-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export class SelectDemo {
latestChangeEvent: MdSelectChange;
floatPlaceholder: string = 'auto';
foodControl = new FormControl('pizza-1');
drinksTheme = 'primary';
pokemonTheme = 'primary';

foods = [
{value: 'steak-0', viewValue: 'Steak'},
Expand Down Expand Up @@ -48,6 +50,12 @@ export class SelectDemo {
{value: 'psyduck-6', viewValue: 'Psyduck'},
];

availableThemes = [
{value: 'primary', name: 'Primary' },
{value: 'accent', name: 'Accent' },
{value: 'warn', name: 'Warn' }
];

toggleDisabled() {
this.foodControl.enabled ? this.foodControl.disable() : this.foodControl.enable();
}
Expand Down
21 changes: 15 additions & 6 deletions src/lib/core/option/_option-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,29 @@
$foreground: map-get($theme, foreground);
$background: map-get($theme, background);
$primary: map-get($theme, primary);
$accent: map-get($theme, accent);
$warn: map-get($theme, warn);

.mat-option {
&:hover:not(.mat-option-disabled), &:focus:not(.mat-option-disabled) {
background: mat-color($background, hover);
}

&.mat-selected {
&.mat-selected.mat-primary, .mat-primary &.mat-selected {
color: mat-color($primary);
}

&.mat-selected.mat-accent, .mat-accent &.mat-selected {
color: mat-color($accent);
}

// In multiple mode there is a checkbox to show that the option is selected.
&:not(.mat-option-multiple) {
background: mat-color($background, hover);
}
&.mat-selected.mat-warn, .mat-warn &.mat-selected {
color: mat-color($warn);
}

// In multiple mode there is a checkbox to show that the option is selected.
&.mat-selected:not(.mat-option-multiple) {
background: mat-color($background, hover);
}

&.mat-active {
Expand All @@ -28,6 +38,5 @@
&.mat-option-disabled {
color: mat-color($foreground, hint-text);
}

}
}
28 changes: 16 additions & 12 deletions src/lib/core/selection/pseudo-checkbox/_pseudo-checkbox-theme.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
@import '../../theming/theming';

@mixin _mat-pseudo-checkbox-inner-content-theme($theme, $pallete-name) {
$pallete: map-get($theme, $pallete-name);
$color: mat-color($pallete, 500);

.mat-pseudo-checkbox-checked.mat-#{$pallete-name},
.mat-pseudo-checkbox-indeterminate.mat-#{$pallete-name},
.mat-#{$pallete-name} .mat-pseudo-checkbox-checked,
.mat-#{$pallete-name} .mat-pseudo-checkbox-indeterminate {
background: $color;
}
}

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

.mat-pseudo-checkbox {
color: mat-color(map-get($theme, foreground), secondary-text);
Expand All @@ -23,19 +35,11 @@
}
}

.mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate {
&.mat-primary {
background: mat-color($primary, 500);
}

&.mat-accent {
background: mat-color($accent, 500);
}

&.mat-warn {
background: mat-color($warn, 500);
}
@include _mat-pseudo-checkbox-inner-content-theme($theme, primary);
@include _mat-pseudo-checkbox-inner-content-theme($theme, accent);
@include _mat-pseudo-checkbox-inner-content-theme($theme, warn);

.mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate {
&.mat-pseudo-checkbox-disabled {
background: $disabled-color;
}
Expand Down
60 changes: 29 additions & 31 deletions src/lib/select/_select-theme.scss
Original file line number Diff line number Diff line change
@@ -1,46 +1,33 @@
@import '../core/theming/palette';
@import '../core/theming/theming';

@mixin _mat-select-inner-content-theme($palette) {
$color: mat-color($palette);

.mat-select-trigger, .mat-select-arrow {
color: $color;
}

.mat-select-underline {
background-color: $color;
}
}

@mixin mat-select-theme($theme) {
$foreground: map-get($theme, foreground);
$background: map-get($theme, background);
$primary: map-get($theme, primary);
$accent: map-get($theme, accent);
$warn: map-get($theme, warn);

.mat-select-trigger {
color: mat-color($foreground, hint-text);

.mat-select:focus:not(.mat-select-disabled) & {
color: mat-color($primary);
}

.mat-select:not(:focus).ng-invalid.ng-touched:not(.mat-select-disabled) & {
color: mat-color($warn);
}
}

.mat-select-underline {
background-color: mat-color($foreground, divider);

.mat-select:focus:not(.mat-select-disabled) & {
background-color: mat-color($primary);
}

.mat-select:not(:focus).ng-invalid.ng-touched:not(.mat-select-disabled) & {
background-color: mat-color($warn);
}
}

.mat-select-arrow {
.mat-select-disabled .mat-select-value,
.mat-select-arrow,
.mat-select-trigger {
color: mat-color($foreground, hint-text);

.mat-select:focus:not(.mat-select-disabled) & {
color: mat-color($primary);
}

.mat-select:not(:focus).ng-invalid.ng-touched:not(.mat-select-disabled) & {
color: mat-color($warn);
}
}

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

.mat-select-value {
color: mat-color($foreground, text);
}

.mat-select-disabled & {
color: mat-color($foreground, hint-text);
.mat-select:focus:not(.mat-select-disabled) {
&.mat-primary {
@include _mat-select-inner-content-theme($primary);
}

&.mat-accent {
@include _mat-select-inner-content-theme($accent);
}
}

.mat-select:focus:not(.mat-select-disabled).mat-warn,
.mat-select:not(:focus).ng-invalid.ng-touched:not(.mat-select-disabled) {
@include _mat-select-inner-content-theme($warn);
}
}
2 changes: 1 addition & 1 deletion src/lib/select/select.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
[offsetY]="_offsetY" [offsetX]="_offsetX" (attach)="_setScrollTop()">
<div class="mat-select-panel" [@transformPanel]="'showing'" (@transformPanel.done)="_onPanelDone()"
(keydown)="_keyManager.onKeydown($event)" [style.transformOrigin]="_transformOrigin"
[class.mat-select-panel-done-animating]="_panelDoneAnimating">
[class.mat-select-panel-done-animating]="_panelDoneAnimating" [ngClass]="'mat-' + color">
<div class="mat-select-content" [@fadeInContent]="'showing'" (@fadeInContent.done)="_onFadeInDone()">
<ng-content></ng-content>
</div>
Expand Down
66 changes: 65 additions & 1 deletion src/lib/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ describe('MdSelect', () => {
SelectWithPlainTabindex,
SelectEarlyAccessSibling,
BasicSelectInitiallyHidden,
BasicSelectNoPlaceholder
BasicSelectNoPlaceholder,
BasicSelectWithTheming
],
providers: [
{provide: OverlayContainer, useFactory: () => {
Expand Down Expand Up @@ -1694,6 +1695,55 @@ describe('MdSelect', () => {

});

describe('theming', () => {
let fixture: ComponentFixture<BasicSelectWithTheming>;
let testInstance: BasicSelectWithTheming;
let selectElement: HTMLElement;

beforeEach(async(() => {
fixture = TestBed.createComponent(BasicSelectWithTheming);
testInstance = fixture.componentInstance;
fixture.detectChanges();

selectElement = fixture.debugElement.query(By.css('.mat-select')).nativeElement;
}));

it('should default to the primary theme', () => {
expect(fixture.componentInstance.select.color).toBe('primary');
expect(selectElement.classList).toContain('mat-primary');
});

it('should be able to override the theme', () => {
fixture.componentInstance.theme = 'accent';
fixture.detectChanges();

expect(fixture.componentInstance.select.color).toBe('accent');
expect(selectElement.classList).toContain('mat-accent');
expect(selectElement.classList).not.toContain('mat-primary');
});

it('should not be able to set a blank theme', () => {
fixture.componentInstance.theme = '';
fixture.detectChanges();

expect(fixture.componentInstance.select.color).toBe('primary');
expect(selectElement.classList).toContain('mat-primary');
});

it('should pass the theme to the panel', () => {
fixture.componentInstance.theme = 'warn';
fixture.debugElement.query(By.css('.mat-select-trigger')).nativeElement.click();
fixture.detectChanges();

const panel = overlayContainerElement.querySelector('.mat-select-panel');

expect(fixture.componentInstance.select.color).toBe('warn');
expect(selectElement.classList).toContain('mat-warn');
expect(panel.classList).toContain('mat-warn');
});

});

});


Expand Down Expand Up @@ -2025,6 +2075,20 @@ class BasicSelectInitiallyHidden {
})
class BasicSelectNoPlaceholder { }

@Component({
selector: 'basic-select-with-theming',
template: `
<md-select placeholder="Food" [color]="theme">
<md-option value="steak-0">Steak</md-option>
<md-option value="pizza-1">Pizza</md-option>
</md-select>
`
})
class BasicSelectWithTheming {
@ViewChild(MdSelect) select: MdSelect;
theme: string;
}

class FakeViewportRuler {
getViewportRect() {
return {
Expand Down
Loading