+ [class.mat-select-panel-done-animating]="_panelDoneAnimating" [ngClass]="'mat-' + color">
diff --git a/src/lib/select/select.spec.ts b/src/lib/select/select.spec.ts
index b53781ede656..60a15fb5bb50 100644
--- a/src/lib/select/select.spec.ts
+++ b/src/lib/select/select.spec.ts
@@ -49,7 +49,8 @@ describe('MdSelect', () => {
SelectWithPlainTabindex,
SelectEarlyAccessSibling,
BasicSelectInitiallyHidden,
- BasicSelectNoPlaceholder
+ BasicSelectNoPlaceholder,
+ BasicSelectWithTheming
],
providers: [
{provide: OverlayContainer, useFactory: () => {
@@ -1694,6 +1695,55 @@ describe('MdSelect', () => {
});
+ describe('theming', () => {
+ let fixture: ComponentFixture
;
+ 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');
+ });
+
+ });
+
});
@@ -2025,6 +2075,20 @@ class BasicSelectInitiallyHidden {
})
class BasicSelectNoPlaceholder { }
+@Component({
+ selector: 'basic-select-with-theming',
+ template: `
+
+ Steak
+ Pizza
+
+ `
+})
+class BasicSelectWithTheming {
+ @ViewChild(MdSelect) select: MdSelect;
+ theme: string;
+}
+
class FakeViewportRuler {
getViewportRect() {
return {
diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts
index 55dd43557a05..a44d58f1d1d2 100644
--- a/src/lib/select/select.ts
+++ b/src/lib/select/select.ts
@@ -9,7 +9,7 @@ import {
Optional,
Output,
QueryList,
- Renderer,
+ Renderer2,
Self,
ViewEncapsulation,
ViewChild,
@@ -111,7 +111,7 @@ export type MdSelectFloatPlaceholderType = 'always' | 'never' | 'auto';
'[class.mat-select-disabled]': 'disabled',
'[class.mat-select]': 'true',
'(keydown)': '_handleKeydown($event)',
- '(blur)': '_onBlur()'
+ '(blur)': '_onBlur()',
},
animations: [
transformPlaceholder,
@@ -157,6 +157,9 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
/** Tab index for the element. */
private _tabIndex: number;
+ /** Theme color for the component. */
+ private _color: string;
+
/**
* The width of the trigger. Must be saved to set the min width of the overlay panel
* and the width of the selected value.
@@ -287,6 +290,17 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
/** Input that can be used to specify the `aria-labelledby` attribute. */
@Input('aria-labelledby') ariaLabelledby: string = '';
+ /** Theme color for the component. */
+ @Input()
+ get color(): string { return this._color; }
+ set color(value: string) {
+ if (value && value !== this._color) {
+ this._renderer.removeClass(this._element.nativeElement, `mat-${this._color}`);
+ this._renderer.addClass(this._element.nativeElement, `mat-${value}`);
+ this._color = value;
+ }
+ }
+
/** Combined stream of all of the child options' change events. */
get optionSelectionChanges(): Observable {
return Observable.merge(...this.options.map(option => option.onSelectionChange));
@@ -301,7 +315,7 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
/** Event emitted when the selected value has been changed by the user. */
@Output() change: EventEmitter = new EventEmitter();
- constructor(private _element: ElementRef, private _renderer: Renderer,
+ constructor(private _element: ElementRef, private _renderer: Renderer2,
private _viewportRuler: ViewportRuler, private _changeDetectorRef: ChangeDetectorRef,
@Optional() private _dir: Dir, @Self() @Optional() public _control: NgControl,
@Attribute('tabindex') tabIndex: string) {
@@ -314,6 +328,7 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
ngOnInit() {
this._selectionModel = new SelectionModel(this.multiple, null, false);
+ this.color = this.color || 'primary';
}
ngAfterContentInit() {
@@ -686,7 +701,7 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
/** Focuses the host element when the panel closes. */
private _focusHost(): void {
- this._renderer.invokeElementMethod(this._element.nativeElement, 'focus');
+ this._element.nativeElement.focus();
}
/** Gets the index of the provided option in the option list. */
From ff1a7980cdf6b224ffcba9cc5c9b8b890a210908 Mon Sep 17 00:00:00 2001
From: crisbeto
Date: Mon, 17 Apr 2017 15:21:41 +0200
Subject: [PATCH 2/3] fix: don't use parent selector in theme and reduce
redundant styles
---
src/lib/select/_select-theme.scss | 79 +++++++++++--------------------
1 file changed, 28 insertions(+), 51 deletions(-)
diff --git a/src/lib/select/_select-theme.scss b/src/lib/select/_select-theme.scss
index 85ec21faef58..d996f4de8165 100644
--- a/src/lib/select/_select-theme.scss
+++ b/src/lib/select/_select-theme.scss
@@ -1,6 +1,18 @@
@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);
@@ -8,60 +20,14 @@
$accent: map-get($theme, accent);
$warn: map-get($theme, warn);
- .mat-select:focus:not(.mat-select-disabled) {
- &.mat-primary {
- .mat-select-trigger, .mat-select-arrow {
- color: mat-color($primary);
- }
-
- .mat-select-underline {
- background-color: mat-color($primary);
- }
- }
-
- &.mat-accent {
- .mat-select-trigger, .mat-select-arrow {
- color: mat-color($accent);
- }
-
- .mat-select-underline {
- background-color: mat-color($accent);
- }
- }
-
- &.mat-warn {
- .mat-select-trigger, .mat-select-arrow {
- color: mat-color($warn);
- }
-
- .mat-select-underline {
- background-color: mat-color($warn);
- }
- }
- }
-
- .mat-select-trigger {
- color: mat-color($foreground, hint-text);
-
- .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: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:not(:focus).ng-invalid.ng-touched:not(.mat-select-disabled) & {
- color: mat-color($warn);
- }
}
.mat-select-content, .mat-select-panel-done-animating {
@@ -70,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);
}
}
From 406b6027c0ad81f5bc23a5524adbde921d9049cf Mon Sep 17 00:00:00 2001
From: crisbeto
Date: Mon, 17 Apr 2017 19:19:36 +0200
Subject: [PATCH 3/3] fix: remove the parent selectors on options
---
src/lib/core/option/_option-theme.scss | 33 +++++++++----------
.../_pseudo-checkbox-theme.scss | 28 +++++++++-------
2 files changed, 31 insertions(+), 30 deletions(-)
diff --git a/src/lib/core/option/_option-theme.scss b/src/lib/core/option/_option-theme.scss
index 8586054555d5..01fcc8585fd2 100644
--- a/src/lib/core/option/_option-theme.scss
+++ b/src/lib/core/option/_option-theme.scss
@@ -13,23 +13,21 @@
background: mat-color($background, hover);
}
- &.mat-selected {
- &.mat-primary, .mat-primary & {
- color: mat-color($primary);
- }
-
- &.mat-accent, .mat-accent & {
- color: mat-color($accent);
- }
-
- &.mat-warn, .mat-warn & {
- color: mat-color($warn);
- }
-
- // 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-primary, .mat-primary &.mat-selected {
+ color: mat-color($primary);
+ }
+
+ &.mat-selected.mat-accent, .mat-accent &.mat-selected {
+ color: mat-color($accent);
+ }
+
+ &.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 {
@@ -40,6 +38,5 @@
&.mat-option-disabled {
color: mat-color($foreground, hint-text);
}
-
}
}
diff --git a/src/lib/core/selection/pseudo-checkbox/_pseudo-checkbox-theme.scss b/src/lib/core/selection/pseudo-checkbox/_pseudo-checkbox-theme.scss
index 6b49fd86ea35..260b8d1601f1 100644
--- a/src/lib/core/selection/pseudo-checkbox/_pseudo-checkbox-theme.scss
+++ b/src/lib/core/selection/pseudo-checkbox/_pseudo-checkbox-theme.scss
@@ -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);
@@ -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);
@@ -23,19 +35,11 @@
}
}
- .mat-pseudo-checkbox-checked, .mat-pseudo-checkbox-indeterminate {
- &.mat-primary, .mat-primary & {
- background: mat-color($primary, 500);
- }
-
- &.mat-accent, .mat-accent & {
- background: mat-color($accent, 500);
- }
-
- &.mat-warn, .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;
}