diff --git a/src/lib/button/button.spec.ts b/src/lib/button/button.spec.ts
index a685b2fb31b9..3204769b8fa3 100644
--- a/src/lib/button/button.spec.ts
+++ b/src/lib/button/button.spec.ts
@@ -38,6 +38,12 @@ describe('MdButton', () => {
fixture.detectChanges();
expect(buttonDebugElement.nativeElement.classList.contains('mat-accent')).toBe(true);
expect(aDebugElement.nativeElement.classList.contains('mat-accent')).toBe(true);
+
+ testComponent.buttonColor = null;
+ fixture.detectChanges();
+
+ expect(buttonDebugElement.nativeElement.classList).not.toContain('mat-accent');
+ expect(aDebugElement.nativeElement.classList).not.toContain('mat-accent');
});
it('should should not clear previous defined classes', () => {
@@ -59,7 +65,6 @@ describe('MdButton', () => {
expect(buttonDebugElement.nativeElement.classList.contains('mat-primary')).toBe(false);
expect(buttonDebugElement.nativeElement.classList.contains('mat-accent')).toBe(true);
expect(buttonDebugElement.nativeElement.classList.contains('custom-class')).toBe(true);
-
});
// Regular button tests
diff --git a/src/lib/button/button.ts b/src/lib/button/button.ts
index 8efc0341250a..073916dbecce 100644
--- a/src/lib/button/button.ts
+++ b/src/lib/button/button.ts
@@ -11,6 +11,7 @@ import {
} from '@angular/core';
import {coerceBooleanProperty, FocusOriginMonitor, Platform} from '../core';
import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled';
+import {CanColor, mixinColor} from '../core/common-behaviors/color';
// TODO(kara): Convert attribute selectors to classes when attr maps become available
@@ -71,8 +72,10 @@ export class MdMiniFabCssMatStyler {}
// Boilerplate for applying mixins to MdButton.
-export class MdButtonBase { }
-export const _MdButtonMixinBase = mixinDisabled(MdButtonBase);
+export class MdButtonBase {
+ constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
+}
+export const _MdButtonMixinBase = mixinColor(mixinDisabled(MdButtonBase));
/**
@@ -89,13 +92,11 @@ export const _MdButtonMixinBase = mixinDisabled(MdButtonBase);
},
templateUrl: 'button.html',
styleUrls: ['button.css'],
- inputs: ['disabled'],
+ inputs: ['disabled', 'color'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class MdButton extends _MdButtonMixinBase implements OnDestroy, CanDisable {
- private _color: string;
-
+export class MdButton extends _MdButtonMixinBase implements OnDestroy, CanDisable, CanColor {
/** Whether the button is round. */
_isRoundButton: boolean = this._hasAttributeWithPrefix('fab', 'mini-fab');
@@ -110,12 +111,11 @@ export class MdButton extends _MdButtonMixinBase implements OnDestroy, CanDisabl
get disableRipple() { return this._disableRipple; }
set disableRipple(v) { this._disableRipple = coerceBooleanProperty(v); }
- constructor(
- private _elementRef: ElementRef,
- private _renderer: Renderer2,
- private _platform: Platform,
- private _focusOriginMonitor: FocusOriginMonitor) {
- super();
+ constructor(renderer: Renderer2,
+ elementRef: ElementRef,
+ private _platform: Platform,
+ private _focusOriginMonitor: FocusOriginMonitor) {
+ super(renderer, elementRef);
this._focusOriginMonitor.monitor(this._elementRef.nativeElement, this._renderer, true);
}
@@ -123,27 +123,6 @@ export class MdButton extends _MdButtonMixinBase implements OnDestroy, CanDisabl
this._focusOriginMonitor.stopMonitoring(this._elementRef.nativeElement);
}
- /** The color of the button. Can be `primary`, `accent`, or `warn`. */
- @Input()
- get color(): string { return this._color; }
- set color(value: string) { this._updateColor(value); }
-
- _updateColor(newColor: string) {
- this._setElementColor(this._color, false);
- this._setElementColor(newColor, true);
- this._color = newColor;
- }
-
- _setElementColor(color: string, isAdd: boolean) {
- if (color != null && color != '') {
- if (isAdd) {
- this._renderer.addClass(this._getHostElement(), `mat-${color}`);
- } else {
- this._renderer.removeClass(this._getHostElement(), `mat-${color}`);
- }
- }
- }
-
/** Focuses the button. */
focus(): void {
this._getHostElement().focus();
@@ -189,18 +168,18 @@ export class MdButton extends _MdButtonMixinBase implements OnDestroy, CanDisabl
'[attr.aria-disabled]': '_isAriaDisabled',
'(click)': '_haltDisabledEvents($event)',
},
- inputs: ['disabled'],
+ inputs: ['disabled', 'color'],
templateUrl: 'button.html',
styleUrls: ['button.css'],
encapsulation: ViewEncapsulation.None
})
export class MdAnchor extends MdButton {
constructor(
- elementRef: ElementRef,
- renderer: Renderer2,
platform: Platform,
- focusOriginMonitor: FocusOriginMonitor) {
- super(elementRef, renderer, platform, focusOriginMonitor);
+ focusOriginMonitor: FocusOriginMonitor,
+ elementRef: ElementRef,
+ renderer: Renderer2) {
+ super(renderer, elementRef, platform, focusOriginMonitor);
}
/** @docs-private */
diff --git a/src/lib/checkbox/checkbox.ts b/src/lib/checkbox/checkbox.ts
index 9874e7697b47..3f3fc279cbe4 100644
--- a/src/lib/checkbox/checkbox.ts
+++ b/src/lib/checkbox/checkbox.ts
@@ -17,6 +17,7 @@ import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {coerceBooleanProperty} from '../core/coercion/boolean-property';
import {FocusOrigin, FocusOriginMonitor, MdRipple, RippleRef} from '../core';
import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled';
+import {CanColor, mixinColor} from '../core/common-behaviors/color';
/** Monotonically increasing integer used to auto-generate unique ids for checkbox components. */
@@ -57,8 +58,10 @@ export class MdCheckboxChange {
}
// Boilerplate for applying mixins to MdCheckbox.
-export class MdCheckboxBase { }
-export const _MdCheckboxMixinBase = mixinDisabled(MdCheckboxBase);
+export class MdCheckboxBase {
+ constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
+}
+export const _MdCheckboxMixinBase = mixinColor(mixinDisabled(MdCheckboxBase), 'accent');
/**
@@ -82,12 +85,12 @@ export const _MdCheckboxMixinBase = mixinDisabled(MdCheckboxBase);
'[class.mat-checkbox-label-before]': 'labelPosition == "before"',
},
providers: [MD_CHECKBOX_CONTROL_VALUE_ACCESSOR],
- inputs: ['disabled'],
+ inputs: ['disabled', 'color'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MdCheckbox extends _MdCheckboxMixinBase
- implements ControlValueAccessor, AfterViewInit, OnDestroy, CanDisable {
+ implements ControlValueAccessor, AfterViewInit, OnDestroy, CanColor, CanDisable {
/**
* Attached to the aria-label attribute of the host element. In most cases, arial-labelledby will
* take precedence so this may be omitted.
@@ -183,19 +186,16 @@ export class MdCheckbox extends _MdCheckboxMixinBase
private _indeterminate: boolean = false;
- private _color: string;
-
private _controlValueAccessorChangeFn: (value: any) => void = (value) => {};
/** Reference to the focused state ripple. */
private _focusRipple: RippleRef;
- constructor(private _renderer: Renderer2,
- private _elementRef: ElementRef,
+ constructor(renderer: Renderer2,
+ elementRef: ElementRef,
private _changeDetectorRef: ChangeDetectorRef,
private _focusOriginMonitor: FocusOriginMonitor) {
- super();
- this.color = 'accent';
+ super(renderer, elementRef);
}
ngAfterViewInit() {
@@ -247,27 +247,6 @@ export class MdCheckbox extends _MdCheckboxMixinBase
}
}
- /** The color of the button. Can be `primary`, `accent`, or `warn`. */
- @Input()
- get color(): string { return this._color; }
- set color(value: string) { this._updateColor(value); }
-
- _updateColor(newColor: string) {
- this._setElementColor(this._color, false);
- this._setElementColor(newColor, true);
- this._color = newColor;
- }
-
- _setElementColor(color: string, isAdd: boolean) {
- if (color != null && color != '') {
- if (isAdd) {
- this._renderer.addClass(this._elementRef.nativeElement, `mat-${color}`);
- } else {
- this._renderer.removeClass(this._elementRef.nativeElement, `mat-${color}`);
- }
- }
- }
-
_isRippleDisabled() {
return this.disableRipple || this.disabled;
}
diff --git a/src/lib/chips/chip.ts b/src/lib/chips/chip.ts
index 5e06c3839994..da89aa89ee47 100644
--- a/src/lib/chips/chip.ts
+++ b/src/lib/chips/chip.ts
@@ -11,11 +11,19 @@ import {
import {Focusable} from '../core/a11y/focus-key-manager';
import {coerceBooleanProperty} from '../core/coercion/boolean-property';
+import {CanColor, mixinColor} from '../core/common-behaviors/color';
export interface MdChipEvent {
chip: MdChip;
}
+// Boilerplate for applying mixins to MdChip.
+export class MdChipBase {
+ constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
+}
+export const _MdChipMixinBase = mixinColor(MdChipBase, 'primary');
+
+
/**
* Material design styled Chip component. Used inside the MdChipList component.
*/
@@ -23,6 +31,7 @@ export interface MdChipEvent {
selector: `md-basic-chip, [md-basic-chip], md-chip, [md-chip],
mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]`,
template: ``,
+ inputs: ['color'],
host: {
'[class.mat-chip]': 'true',
'tabindex': '-1',
@@ -35,7 +44,7 @@ export interface MdChipEvent {
'(click)': '_handleClick($event)'
}
})
-export class MdChip implements Focusable, OnInit, OnDestroy {
+export class MdChip extends _MdChipMixinBase implements Focusable, OnInit, OnDestroy, CanColor {
/** Whether or not the chip is disabled. Disabled chips cannot be focused. */
protected _disabled: boolean = null;
@@ -43,9 +52,6 @@ export class MdChip implements Focusable, OnInit, OnDestroy {
/** Whether or not the chip is selected. */
protected _selected: boolean = false;
- /** The palette color of selected chips. */
- protected _color: string = 'primary';
-
/** Emitted when the chip is focused. */
onFocus = new EventEmitter();
@@ -58,11 +64,12 @@ export class MdChip implements Focusable, OnInit, OnDestroy {
/** Emitted when the chip is destroyed. */
@Output() destroy = new EventEmitter();
- constructor(protected _renderer: Renderer2, protected _elementRef: ElementRef) { }
+ constructor(renderer: Renderer2, elementRef: ElementRef) {
+ super(renderer, elementRef);
+ }
ngOnInit(): void {
this._addDefaultCSSClass();
- this._updateColor(this._color);
}
ngOnDestroy(): void {
@@ -108,15 +115,6 @@ export class MdChip implements Focusable, OnInit, OnDestroy {
return this.selected;
}
- /** The color of the chip. Can be `primary`, `accent`, or `warn`. */
- @Input() get color(): string {
- return this._color;
- }
-
- set color(value: string) {
- this._updateColor(value);
- }
-
/** Allows for programmatic focusing of the chip. */
focus(): void {
this._elementRef.nativeElement.focus();
@@ -147,22 +145,4 @@ export class MdChip implements Focusable, OnInit, OnDestroy {
this._renderer.addClass(el, 'mat-basic-chip');
}
}
-
- /** Updates the private _color variable and the native element. */
- private _updateColor(newColor: string) {
- this._setElementColor(this._color, false);
- this._setElementColor(newColor, true);
- this._color = newColor;
- }
-
- /** Sets the mat-color on the native element. */
- private _setElementColor(color: string, isAdd: boolean) {
- if (color != null && color != '') {
- if (isAdd) {
- this._renderer.addClass(this._elementRef.nativeElement, `mat-${color}`);
- } else {
- this._renderer.removeClass(this._elementRef.nativeElement, `mat-${color}`);
- }
- }
- }
}
diff --git a/src/lib/core/common-behaviors/color.spec.ts b/src/lib/core/common-behaviors/color.spec.ts
new file mode 100644
index 000000000000..580d8fda93de
--- /dev/null
+++ b/src/lib/core/common-behaviors/color.spec.ts
@@ -0,0 +1,84 @@
+import {mixinColor} from './color';
+import {ElementRef, Renderer2} from '@angular/core';
+
+describe('MixinColor', () => {
+
+ it('should augment an existing class with a color property', () => {
+ const classWithColor = mixinColor(TestClass);
+ const instance = new classWithColor();
+
+ expect(instance.color)
+ .toBeFalsy('Expected the mixed-into class to have a color property');
+
+ instance.color = 'accent';
+
+ expect(instance.color)
+ .toBe('accent', 'Expected the mixed-into class to have an updated color property');
+ });
+
+ it('should remove old color classes if new color is set', () => {
+ const classWithColor = mixinColor(TestClass);
+ const instance = new classWithColor();
+
+ expect(instance.testElement.classList.length)
+ .toBe(0, 'Expected the element to not have any classes at initialization');
+
+ instance.color = 'primary';
+
+ expect(instance.testElement.classList)
+ .toContain('mat-primary', 'Expected the element to have the "mat-primary" class set');
+
+ instance.color = 'accent';
+
+ expect(instance.testElement.classList)
+ .not.toContain('mat-primary', 'Expected the element to no longer have "mat-primary" set.');
+ expect(instance.testElement.classList)
+ .toContain('mat-accent', 'Expected the element to have the "mat-accent" class set');
+ });
+
+ it('should allow having no color set', () => {
+ const classWithColor = mixinColor(TestClass);
+ const instance = new classWithColor();
+
+ expect(instance.testElement.classList.length)
+ .toBe(0, 'Expected the element to not have any classes at initialization');
+
+ instance.color = 'primary';
+
+ expect(instance.testElement.classList)
+ .toContain('mat-primary', 'Expected the element to have the "mat-primary" class set');
+
+ instance.color = null;
+
+ expect(instance.testElement.classList.length)
+ .toBe(0, 'Expected the element to have no color class set.');
+ });
+
+ it('should allow having a default color if specified', () => {
+ const classWithColor = mixinColor(TestClass, 'accent');
+ const instance = new classWithColor();
+
+
+ expect(instance.testElement.classList)
+ .toContain('mat-accent', 'Expected the element to have the "mat-accent" class by default.');
+
+ instance.color = null;
+
+ expect(instance.testElement.classList)
+ .toContain('mat-accent', 'Expected the default color "mat-accent" to be set.');
+ });
+
+});
+
+class TestClass {
+ testElement: HTMLElement = document.createElement('div');
+
+ /** Mock of a RendererV2 for the color mixin. */
+ _renderer: Renderer2 = {
+ addClass: (element: HTMLElement, className: string) => element.classList.add(className),
+ removeClass: (element: HTMLElement, className: string) => element.classList.remove(className)
+ } as any;
+
+ /** Fake instance of an ElementRef. */
+ _elementRef = new ElementRef(this.testElement);
+}
diff --git a/src/lib/core/common-behaviors/color.ts b/src/lib/core/common-behaviors/color.ts
new file mode 100644
index 000000000000..82855231726d
--- /dev/null
+++ b/src/lib/core/common-behaviors/color.ts
@@ -0,0 +1,48 @@
+import {Constructor} from './constructor';
+import {ElementRef, Renderer2} from '@angular/core';
+
+/** @docs-private */
+export interface CanColor {
+ color: string;
+}
+
+/** @docs-private */
+export interface HasRenderer {
+ _renderer: Renderer2;
+ _elementRef: ElementRef;
+}
+
+/** Possible color palette values. */
+export type ThemePalette = 'primary' | 'accent' | 'warn' | null;
+
+/** Mixin to augment a directive with a `color` property. */
+export function mixinColor>(base: T, defaultColor?: ThemePalette)
+ : Constructor & T {
+ return class extends base {
+ private _color: ThemePalette = null;
+
+ get color(): ThemePalette { return this._color; }
+ set color(value: ThemePalette) {
+ const colorPalette = value || defaultColor;
+
+ if (colorPalette !== this._color) {
+ if (this._color) {
+ this._renderer.removeClass(this._elementRef.nativeElement, `mat-${this._color}`);
+ }
+ if (colorPalette) {
+ this._renderer.addClass(this._elementRef.nativeElement, `mat-${colorPalette}`);
+ }
+
+ this._color = colorPalette;
+ }
+ }
+
+ constructor(...args: any[]) {
+ super(...args);
+
+ // Set the default color that can be specified from the mixin.
+ this.color = defaultColor;
+ }
+ };
+}
+
diff --git a/src/lib/core/common-behaviors/constructor.ts b/src/lib/core/common-behaviors/constructor.ts
new file mode 100644
index 000000000000..5a695a1b4d23
--- /dev/null
+++ b/src/lib/core/common-behaviors/constructor.ts
@@ -0,0 +1,2 @@
+/** @docs-private */
+export type Constructor = new(...args: any[]) => T;
diff --git a/src/lib/core/common-behaviors/disabled.ts b/src/lib/core/common-behaviors/disabled.ts
index 8c290d1e8fdd..5db4d2968f2d 100644
--- a/src/lib/core/common-behaviors/disabled.ts
+++ b/src/lib/core/common-behaviors/disabled.ts
@@ -1,8 +1,5 @@
import {coerceBooleanProperty} from '../coercion/boolean-property';
-
-
-/** @docs-private */
-export type Constructor = new(...args: any[]) => T;
+import {Constructor} from './constructor';
/** @docs-private */
export interface CanDisable {
diff --git a/src/lib/core/selection/pseudo-checkbox/pseudo-checkbox.ts b/src/lib/core/selection/pseudo-checkbox/pseudo-checkbox.ts
index 8b17c2e3fd48..ced221138036 100644
--- a/src/lib/core/selection/pseudo-checkbox/pseudo-checkbox.ts
+++ b/src/lib/core/selection/pseudo-checkbox/pseudo-checkbox.ts
@@ -5,9 +5,18 @@ import {
ElementRef,
Renderer2,
} from '@angular/core';
+import {CanColor, mixinColor} from '../../common-behaviors/color';
export type MdPseudoCheckboxState = 'unchecked' | 'checked' | 'indeterminate';
+
+// Boilerplate for applying mixins to MdChip.
+export class MdPseudoCheckboxBase {
+ constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
+}
+export const _MdPseudoCheckboxBase = mixinColor(MdPseudoCheckboxBase, 'accent');
+
+
/**
* Component that shows a simplified checkbox without including any kind of "real" checkbox.
* Meant to be used when the checkbox is purely decorative and a large number of them will be
@@ -24,6 +33,7 @@ export type MdPseudoCheckboxState = 'unchecked' | 'checked' | 'indeterminate';
encapsulation: ViewEncapsulation.None,
selector: 'md-pseudo-checkbox, mat-pseudo-checkbox',
styleUrls: ['pseudo-checkbox.css'],
+ inputs: ['color'],
template: '',
host: {
'[class.mat-pseudo-checkbox]': 'true',
@@ -32,29 +42,14 @@ export type MdPseudoCheckboxState = 'unchecked' | 'checked' | 'indeterminate';
'[class.mat-pseudo-checkbox-disabled]': 'disabled',
},
})
-export class MdPseudoCheckbox {
+export class MdPseudoCheckbox extends _MdPseudoCheckboxBase implements CanColor {
/** Display state of the checkbox. */
@Input() state: MdPseudoCheckboxState = 'unchecked';
/** Whether the checkbox is disabled. */
@Input() disabled: boolean = false;
- /** Color of the checkbox. */
- @Input()
- get color(): string { return this._color; }
- set color(value: string) {
- if (value) {
- let nativeElement = this._elementRef.nativeElement;
-
- this._renderer.removeClass(nativeElement, `mat-${this.color}`);
- this._renderer.addClass(nativeElement, `mat-${value}`);
- this._color = value;
- }
- }
-
- private _color: string;
-
- constructor(private _elementRef: ElementRef, private _renderer: Renderer2) {
- this.color = 'accent';
+ constructor(elementRef: ElementRef, renderer: Renderer2) {
+ super(renderer, elementRef);
}
}
diff --git a/src/lib/icon/icon.ts b/src/lib/icon/icon.ts
index 83b1027d1726..666291acfa9a 100644
--- a/src/lib/icon/icon.ts
+++ b/src/lib/icon/icon.ts
@@ -11,6 +11,14 @@ import {
AfterViewChecked,
} from '@angular/core';
import {MdIconRegistry} from './icon-registry';
+import {CanColor, mixinColor} from '../core/common-behaviors/color';
+
+
+// Boilerplate for applying mixins to MdIcon.
+export class MdIconBase {
+ constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
+}
+export const _MdIconMixinBase = mixinColor(MdIconBase);
/**
@@ -51,6 +59,7 @@ import {MdIconRegistry} from './icon-registry';
template: '',
selector: 'md-icon, mat-icon',
styleUrls: ['icon.css'],
+ inputs: ['color'],
host: {
'role': 'img',
'[class.mat-icon]': 'true',
@@ -58,8 +67,8 @@ import {MdIconRegistry} from './icon-registry';
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class MdIcon implements OnChanges, OnInit, AfterViewChecked {
- private _color: string;
+export class MdIcon extends _MdIconMixinBase implements OnChanges, OnInit, AfterViewChecked,
+ CanColor {
/** Name of the icon in the SVG icon set. */
@Input() svgIcon: string;
@@ -76,34 +85,14 @@ export class MdIcon implements OnChanges, OnInit, AfterViewChecked {
/** Screenreader label for the icon. */
@Input('aria-label') hostAriaLabel: string = '';
- /** Color of the icon. */
- @Input()
- get color(): string { return this._color; }
- set color(value: string) { this._updateColor(value); }
-
private _previousFontSetClass: string;
private _previousFontIconClass: string;
private _previousAriaLabel: string;
- constructor(
- private _elementRef: ElementRef,
- private _renderer: Renderer2,
- private _mdIconRegistry: MdIconRegistry) { }
-
- _updateColor(newColor: string) {
- this._setElementColor(this._color, false);
- this._setElementColor(newColor, true);
- this._color = newColor;
- }
-
- _setElementColor(color: string, isAdd: boolean) {
- if (color != null && color != '') {
- if (isAdd) {
- this._renderer.addClass(this._elementRef.nativeElement, `mat-${color}`);
- } else {
- this._renderer.removeClass(this._elementRef.nativeElement, `mat-${color}`);
- }
- }
+ constructor(private _mdIconRegistry: MdIconRegistry,
+ renderer: Renderer2,
+ elementRef: ElementRef) {
+ super(renderer, elementRef);
}
/**
diff --git a/src/lib/progress-spinner/progress-spinner.ts b/src/lib/progress-spinner/progress-spinner.ts
index a88fef129c72..b9265e2e5079 100644
--- a/src/lib/progress-spinner/progress-spinner.ts
+++ b/src/lib/progress-spinner/progress-spinner.ts
@@ -10,6 +10,7 @@ import {
Directive,
ViewChild,
} from '@angular/core';
+import {CanColor, mixinColor} from '../core/common-behaviors/color';
// TODO(josephperrott): Benchpress tests.
@@ -49,6 +50,11 @@ type EasingFn = (currentTime: number, startValue: number,
})
export class MdProgressSpinnerCssMatStyler {}
+// Boilerplate for applying mixins to MdProgressSpinner.
+export class MdProgressSpinnerBase {
+ constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
+}
+export const _MdProgressSpinnerMixinBase = mixinColor(MdProgressSpinnerBase, 'primary');
/**
* component.
@@ -61,11 +67,14 @@ export class MdProgressSpinnerCssMatStyler {}
'[attr.aria-valuemin]': '_ariaValueMin',
'[attr.aria-valuemax]': '_ariaValueMax'
},
+ inputs: ['color'],
templateUrl: 'progress-spinner.html',
styleUrls: ['progress-spinner.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class MdProgressSpinner implements OnDestroy {
+export class MdProgressSpinner extends _MdProgressSpinnerMixinBase
+ implements OnDestroy, CanColor {
+
/** The id of the last requested animation. */
private _lastAnimationId: number = 0;
@@ -77,7 +86,6 @@ export class MdProgressSpinner implements OnDestroy {
private _mode: ProgressSpinnerMode = 'determinate';
private _value: number;
- private _color: string = 'primary';
/** Stroke width of the progress spinner. By default uses 10px as stroke width. */
@Input() strokeWidth: number = PROGRESS_SPINNER_STROKE_WIDTH;
@@ -112,17 +120,6 @@ export class MdProgressSpinner implements OnDestroy {
this._cleanupIndeterminateAnimation();
}
- /** The color of the progress-spinner. Can be primary, accent, or warn. */
- @Input()
- get color(): string { return this._color; }
- set color(value: string) {
- if (value) {
- this._renderer.removeClass(this._elementRef.nativeElement, `mat-${this._color}`);
- this._renderer.addClass(this._elementRef.nativeElement, `mat-${value}`);
- this._color = value;
- }
- }
-
/** Value of the progress circle. It is bound to the host as the attribute aria-valuenow. */
@Input()
@HostBinding('attr.aria-valuenow')
@@ -162,10 +159,11 @@ export class MdProgressSpinner implements OnDestroy {
}
}
- constructor(
- private _ngZone: NgZone,
- private _elementRef: ElementRef,
- private _renderer: Renderer2) { }
+ constructor(renderer: Renderer2,
+ elementRef: ElementRef,
+ private _ngZone: NgZone) {
+ super(renderer, elementRef);
+ }
/**
@@ -274,13 +272,14 @@ export class MdProgressSpinner implements OnDestroy {
'mode': 'indeterminate',
'[class.mat-spinner]': 'true',
},
+ inputs: ['color'],
templateUrl: 'progress-spinner.html',
styleUrls: ['progress-spinner.css'],
})
export class MdSpinner extends MdProgressSpinner implements OnDestroy {
constructor(elementRef: ElementRef, ngZone: NgZone, renderer: Renderer2) {
- super(ngZone, elementRef, renderer);
+ super(renderer, elementRef, ngZone);
this.mode = 'indeterminate';
}
diff --git a/src/lib/select/select.ts b/src/lib/select/select.ts
index a99d08220dcb..c972c1a6586d 100644
--- a/src/lib/select/select.ts
+++ b/src/lib/select/select.ts
@@ -34,6 +34,8 @@ import {getMdSelectDynamicMultipleError, getMdSelectNonArrayValueError} from './
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/operator/filter';
+import {CanColor, mixinColor} from '../core/common-behaviors/color';
+import {CanDisable} from '../core/common-behaviors/disabled';
/**
@@ -95,11 +97,19 @@ export class MdSelectChange {
/** Allowed values for the floatPlaceholder option. */
export type MdSelectFloatPlaceholderType = 'always' | 'never' | 'auto';
+// Boilerplate for applying mixins to MdSelect.
+export class MdSelectBase {
+ constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
+}
+export const _MdSelectMixinBase = mixinColor(MdSelectBase, 'primary');
+
+
@Component({
moduleId: module.id,
selector: 'md-select, mat-select',
templateUrl: 'select.html',
styleUrls: ['select.css'],
+ inputs: ['color'],
encapsulation: ViewEncapsulation.None,
host: {
'role': 'listbox',
@@ -122,7 +132,8 @@ export type MdSelectFloatPlaceholderType = 'always' | 'never' | 'auto';
],
exportAs: 'mdSelect',
})
-export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlValueAccessor {
+export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, OnDestroy, OnInit,
+ ControlValueAccessor, CanColor {
/** Whether or not the overlay panel is open. */
private _panelOpen = false;
@@ -159,9 +170,6 @@ 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.
@@ -288,17 +296,6 @@ 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));
@@ -313,10 +310,14 @@ 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: Renderer2,
- private _viewportRuler: ViewportRuler, private _changeDetectorRef: ChangeDetectorRef,
- @Optional() private _dir: Dir, @Self() @Optional() public _control: NgControl,
+ constructor(private _viewportRuler: ViewportRuler,
+ private _changeDetectorRef: ChangeDetectorRef,
+ renderer: Renderer2,
+ elementRef: ElementRef,
+ @Optional() private _dir: Dir,
+ @Self() @Optional() public _control: NgControl,
@Attribute('tabindex') tabIndex: string) {
+ super(renderer, elementRef);
if (this._control) {
this._control.valueAccessor = this;
@@ -327,7 +328,6 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
ngOnInit() {
this._selectionModel = new SelectionModel(this.multiple, null, false);
- this.color = this.color || 'primary';
}
ngAfterContentInit() {
@@ -742,7 +742,7 @@ export class MdSelect implements AfterContentInit, OnDestroy, OnInit, ControlVal
/** Focuses the host element when the panel closes. */
private _focusHost(): void {
- this._element.nativeElement.focus();
+ this._elementRef.nativeElement.focus();
}
/** Gets the index of the provided option in the option list. */
diff --git a/src/lib/slide-toggle/slide-toggle.ts b/src/lib/slide-toggle/slide-toggle.ts
index b4e6415bf7b4..294e16a8e969 100644
--- a/src/lib/slide-toggle/slide-toggle.ts
+++ b/src/lib/slide-toggle/slide-toggle.ts
@@ -24,6 +24,7 @@ import {
} from '../core';
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled';
+import {CanColor, mixinColor} from '../core/common-behaviors/color';
export const MD_SLIDE_TOGGLE_VALUE_ACCESSOR: any = {
@@ -44,8 +45,10 @@ let nextId = 0;
// Boilerplate for applying mixins to MdSlideToggle.
-export class MdSlideToggleBase { }
-export const _MdSlideToggleMixinBase = mixinDisabled(MdSlideToggleBase);
+export class MdSlideToggleBase {
+ constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
+}
+export const _MdSlideToggleMixinBase = mixinColor(mixinDisabled(MdSlideToggleBase), 'accent');
/** Represents a slidable "switch" toggle that can be moved between on and off. */
@Component({
@@ -60,19 +63,18 @@ export const _MdSlideToggleMixinBase = mixinDisabled(MdSlideToggleBase);
templateUrl: 'slide-toggle.html',
styleUrls: ['slide-toggle.css'],
providers: [MD_SLIDE_TOGGLE_VALUE_ACCESSOR],
- inputs: ['disabled'],
+ inputs: ['disabled', 'color'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MdSlideToggle extends _MdSlideToggleMixinBase
- implements OnDestroy, AfterContentInit, ControlValueAccessor, CanDisable {
+ implements OnDestroy, AfterContentInit, ControlValueAccessor, CanDisable, CanColor {
private onChange = (_: any) => {};
private onTouched = () => {};
// A unique id for the slide-toggle. By default the id is auto-generated.
private _uniqueId = `md-slide-toggle-${++nextId}`;
private _checked: boolean = false;
- private _color: string;
private _slideRenderer: SlideToggleRenderer = null;
private _required: boolean = false;
private _disableRipple: boolean = false;
@@ -120,11 +122,11 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase
/** Reference to the ripple directive on the thumb container. */
@ViewChild(MdRipple) _ripple: MdRipple;
- constructor(private _elementRef: ElementRef,
- private _renderer: Renderer2,
+ constructor(elementRef: ElementRef,
+ renderer: Renderer2,
private _focusOriginMonitor: FocusOriginMonitor,
private _changeDetectorRef: ChangeDetectorRef) {
- super();
+ super(renderer, elementRef);
}
ngAfterContentInit() {
@@ -210,13 +212,6 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase
}
}
- /** The color of the slide-toggle. Can be primary, accent, or warn. */
- @Input()
- get color(): string { return this._color; }
- set color(value: string) {
- this._updateColor(value);
- }
-
/** Toggles the checked state of the slide-toggle. */
toggle() {
this.checked = !this.checked;
@@ -238,22 +233,6 @@ export class MdSlideToggle extends _MdSlideToggleMixinBase
}
}
- private _updateColor(newColor: string) {
- this._setElementColor(this._color, false);
- this._setElementColor(newColor, true);
- this._color = newColor;
- }
-
- private _setElementColor(color: string, isAdd: boolean) {
- if (color != null && color != '') {
- if (isAdd) {
- this._renderer.addClass(this._elementRef.nativeElement, `mat-${color}`);
- } else {
- this._renderer.removeClass(this._elementRef.nativeElement, `mat-${color}`);
- }
- }
- }
-
/** Emits the change event to the `change` output EventEmitter */
private _emitChangeEvent() {
let event = new MdSlideToggleChange();
diff --git a/src/lib/toolbar/toolbar.ts b/src/lib/toolbar/toolbar.ts
index fedf302fa950..87d0f85be9b8 100644
--- a/src/lib/toolbar/toolbar.ts
+++ b/src/lib/toolbar/toolbar.ts
@@ -1,12 +1,12 @@
import {
Component,
ChangeDetectionStrategy,
- Input,
ViewEncapsulation,
Directive,
ElementRef,
Renderer2,
} from '@angular/core';
+import {CanColor, mixinColor} from '../core/common-behaviors/color';
@Directive({
@@ -17,11 +17,19 @@ import {
})
export class MdToolbarRow {}
+// Boilerplate for applying mixins to MdToolbar.
+export class MdToolbarBase {
+ constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
+}
+export const _MdToolbarMixinBase = mixinColor(MdToolbarBase);
+
+
@Component({
moduleId: module.id,
selector: 'md-toolbar, mat-toolbar',
templateUrl: 'toolbar.html',
styleUrls: ['toolbar.css'],
+ inputs: ['color'],
host: {
'[class.mat-toolbar]': 'true',
'role': 'toolbar'
@@ -29,38 +37,10 @@ export class MdToolbarRow {}
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None
})
-export class MdToolbar {
-
- private _color: string;
-
- constructor(private _elementRef: ElementRef, private _renderer: Renderer2) { }
-
- /** The color of the toolbar. Can be primary, accent, or warn. */
- @Input()
- get color(): string {
- return this._color;
- }
-
- set color(value: string) {
- this._updateColor(value);
- }
-
- private _updateColor(newColor: string) {
- this._setElementColor(this._color, false);
- this._setElementColor(newColor, true);
- this._color = newColor;
- }
-
- private _setElementColor(color: string, isAdd: boolean) {
- if (color != null && color != '') {
- let element = this._elementRef.nativeElement;
+export class MdToolbar extends _MdToolbarMixinBase implements CanColor {
- if (isAdd) {
- this._renderer.addClass(element, `mat-${color}`);
- } else {
- this._renderer.removeClass(element, `mat-${color}`);
- }
- }
+ constructor(renderer: Renderer2, elementRef: ElementRef) {
+ super(renderer, elementRef);
}
}