Skip to content

Commit

Permalink
feat(tabs): add theming and ability to set background color (#5287)
Browse files Browse the repository at this point in the history
  • Loading branch information
willshowell authored and kara committed Jul 22, 2017
1 parent e8005ec commit 374aaff
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 21 deletions.
31 changes: 30 additions & 1 deletion src/demo-app/tabs/tabs-demo.html
Expand Up @@ -3,9 +3,10 @@ <h1>Tab Nav Bar</h1>
<button md-button (click)="tabLinks.shift()">Remove tab</button>
<button md-button (click)="swapTabLinks()">Swap first two</button>
<button md-button (click)="addToLabel()">Add to labels</button>
<button md-button (click)="toggleBackground()">Toggle background</button>

<div class="demo-nav-bar">
<nav md-tab-nav-bar aria-label="weather navigation links">
<nav md-tab-nav-bar aria-label="weather navigation links" [backgroundColor]="tabNavBackground">
<a md-tab-link
*ngFor="let tabLink of tabLinks; let i = index"
[routerLink]="tabLink.link"
Expand Down Expand Up @@ -248,3 +249,31 @@ <h1>Inverted tabs</h1>
</div>
</md-tab>
</md-tab-group>

<h1>Accent tabs</h1>
<md-tab-group class="demo-tab-group" color="accent">
<md-tab label="Earth">
<div class="tab-content">
This tab is about the Earth!
</div>
</md-tab>
<md-tab label="Fire">
<div class="tab-content">
This tab is about combustion!
</div>
</md-tab>
</md-tab-group>

<h1>Tabs with background color</h1>
<md-tab-group class="demo-tab-group" backgroundColor="primary" color="accent">
<md-tab label="Earth">
<div class="tab-content">
This tab is about the Earth!
</div>
</md-tab>
<md-tab label="Fire">
<div class="tab-content">
This tab is about combustion!
</div>
</md-tab>
</md-tab-group>
6 changes: 6 additions & 0 deletions src/demo-app/tabs/tabs-demo.ts
Expand Up @@ -16,6 +16,8 @@ export class TabsDemo {
{label: 'Fog', link: 'foggy-tab'},
];

tabNavBackground: any = undefined;

// Standard tabs demo
tabs = [
{
Expand Down Expand Up @@ -93,6 +95,10 @@ export class TabsDemo {
addToLabel() {
this.tabLinks.forEach(link => link.label += 'extracontent');
}

toggleBackground() {
this.tabNavBackground = this.tabNavBackground ? undefined : 'primary';
}
}


Expand Down
83 changes: 78 additions & 5 deletions src/lib/tabs/_tabs-theme.scss
Expand Up @@ -23,21 +23,94 @@
}
}

.mat-tab-label:focus {
background-color: mat-color($primary, lighter, 0.3);
.mat-tab-label, .mat-tab-link {
color: mat-color($foreground, text);

&.mat-tab-disabled {
color: mat-color($foreground, disabled-text);
}
}

.mat-tab-header-pagination-chevron {
border-color: mat-color($foreground, text);
}

.mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron {
border-color: mat-color($foreground, disabled-text);
}

// Remove header border when there is a background color
.mat-tab-group[class*='mat-background-'] .mat-tab-header,
.mat-tab-nav-bar[class*='mat-background-'] {
border-bottom: none;
border-top: none;
}

.mat-tab-group, .mat-tab-nav-bar {
$theme-colors: (
primary: $primary,
accent: $accent,
warn: $warn
);

@each $name, $color in $theme-colors {
// Set the foreground color of the tabs
&.mat-#{$name} {
@include _mat-tab-label-focus($color);
@include _mat-ink-bar($color);

// Override ink bar when background color is the same
&.mat-background-#{$name} {
@include _mat-ink-bar($color, default-contrast);
}
}
}

@each $name, $color in $theme-colors {
// Set background color of the tabs and override focus color
&.mat-background-#{$name} {
@include _mat-tab-label-focus($color);
@include _mat-tabs-background($color);
}
}
}
}

@mixin _mat-ink-bar($color, $hue: default) {
.mat-ink-bar {
background-color: mat-color($primary);
background-color: mat-color($color, $hue);
}
}

@mixin _mat-tab-label-focus($tab-focus-color) {
.mat-tab-label:focus, .mat-tab-link:focus {
background-color: mat-color($tab-focus-color, lighter, 0.3);
}
}

@mixin _mat-tabs-background($background-color) {
// Set background color for the tab group
.mat-tab-header, .mat-tab-links {
background-color: mat-color($background-color);
}

// Set labels to contrast against background
.mat-tab-label, .mat-tab-link {
color: mat-color($foreground, text);
color: mat-color($background-color, default-contrast);

&.mat-tab-disabled {
color: mat-color($foreground, disabled-text);
color: mat-color($background-color, default-contrast, 0.4);
}
}

// Set pagination chevrons to contrast background
.mat-tab-header-pagination-chevron {
border-color: mat-color($background-color, default-contrast);
}

.mat-tab-header-pagination-disabled .mat-tab-header-pagination-chevron {
border-color: mat-color($background-color, default-contrast, 0.4);
}
}

@mixin mat-tabs-typography($config) {
Expand Down
33 changes: 27 additions & 6 deletions src/lib/tabs/tab-group.ts
Expand Up @@ -30,6 +30,7 @@ import {MdTab} from './tab';
import {map} from '../core/rxjs/index';
import {merge} from 'rxjs/observable/merge';
import {CanDisableRipple, mixinDisableRipple} from '../core/common-behaviors/disable-ripple';
import {CanColor, mixinColor, ThemePalette} from '../core/common-behaviors/color';


/** Used to generate unique ID's for each tab component */
Expand All @@ -46,8 +47,10 @@ export type MdTabHeaderPosition = 'above' | 'below';

// Boilerplate for applying mixins to MdTabGroup.
/** @docs-private */
export class MdTabGroupBase {}
export const _MdTabGroupMixinBase = mixinDisableRipple(MdTabGroupBase);
export class MdTabGroupBase {
constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
}
export const _MdTabGroupMixinBase = mixinColor(mixinDisableRipple(MdTabGroupBase), 'primary');

/**
* Material design tab-group component. Supports basic tab pairs (label + content) and includes
Expand All @@ -60,15 +63,15 @@ export const _MdTabGroupMixinBase = mixinDisableRipple(MdTabGroupBase);
templateUrl: 'tab-group.html',
styleUrls: ['tab-group.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
inputs: ['disableRipple'],
inputs: ['color', 'disableRipple'],
host: {
'class': 'mat-tab-group',
'[class.mat-tab-group-dynamic-height]': 'dynamicHeight',
'[class.mat-tab-group-inverted-header]': 'headerPosition === "below"',
}
})
export class MdTabGroup extends _MdTabGroupMixinBase implements AfterContentInit,
AfterContentChecked, AfterViewChecked, OnDestroy, CanDisableRipple {
AfterContentChecked, AfterViewChecked, OnDestroy, CanColor, CanDisableRipple {

@ContentChildren(MdTab) _tabs: QueryList<MdTab>;

Expand Down Expand Up @@ -109,6 +112,22 @@ export class MdTabGroup extends _MdTabGroupMixinBase implements AfterContentInit
/** Position of the tab header. */
@Input() headerPosition: MdTabHeaderPosition = 'above';

/** Background color of the tab group. */
@Input()
get backgroundColor(): ThemePalette { return this._backgroundColor; }
set backgroundColor(value: ThemePalette) {
let nativeElement = this._elementRef.nativeElement;

this._renderer.removeClass(nativeElement, `mat-background-${this.backgroundColor}`);

if (value) {
this._renderer.addClass(nativeElement, `mat-background-${value}`);
}

this._backgroundColor = value;
}
private _backgroundColor: ThemePalette;

/** Output to enable support for two-way binding on `[(selectedIndex)]` */
@Output() get selectedIndexChange(): Observable<number> {
return map.call(this.selectChange, event => event.index);
Expand All @@ -122,8 +141,10 @@ export class MdTabGroup extends _MdTabGroupMixinBase implements AfterContentInit

private _groupId: number;

constructor(private _renderer: Renderer2, private _changeDetectorRef: ChangeDetectorRef) {
super();
constructor(_renderer: Renderer2,
elementRef: ElementRef,
private _changeDetectorRef: ChangeDetectorRef) {
super(_renderer, elementRef);
this._groupId = nextId++;
}

Expand Down
4 changes: 0 additions & 4 deletions src/lib/tabs/tab-header.scss
Expand Up @@ -65,10 +65,6 @@
.mat-tab-header-pagination-disabled {
box-shadow: none;
cursor: default;

.mat-tab-header-pagination-chevron {
border-color: #ccc;
}
}

.mat-tab-label-container {
Expand Down
39 changes: 34 additions & 5 deletions src/lib/tabs/tab-nav-bar/tab-nav-bar.ts
Expand Up @@ -17,6 +17,7 @@ import {
NgZone,
OnDestroy,
Optional,
Renderer2,
ViewChild,
ViewEncapsulation,
ChangeDetectionStrategy,
Expand All @@ -27,27 +28,36 @@ import {CanDisable, mixinDisabled} from '../../core/common-behaviors/disabled';
import {MdRipple} from '../../core';
import {ViewportRuler} from '../../core/overlay/position/viewport-ruler';
import {Directionality, MD_RIPPLE_GLOBAL_OPTIONS, Platform, RippleGlobalOptions} from '../../core';
import {CanColor, mixinColor, ThemePalette} from '../../core/common-behaviors/color';
import {Subject} from 'rxjs/Subject';
import {Subscription} from 'rxjs/Subscription';
import {takeUntil, auditTime} from '../../core/rxjs/index';
import {of as observableOf} from 'rxjs/observable/of';
import {merge} from 'rxjs/observable/merge';
import {fromEvent} from 'rxjs/observable/fromEvent';

// Boilerplate for applying mixins to MdTabNav.
/** @docs-private */
export class MdTabNavBase {
constructor(public _renderer: Renderer2, public _elementRef: ElementRef) {}
}
export const _MdTabNavMixinBase = mixinColor(MdTabNavBase, 'primary');

/**
* Navigation component matching the styles of the tab group header.
* Provides anchored navigation with animated ink bar.
*/
@Component({
moduleId: module.id,
selector: '[md-tab-nav-bar], [mat-tab-nav-bar]',
inputs: ['color'],
templateUrl: 'tab-nav-bar.html',
styleUrls: ['tab-nav-bar.css'],
host: {'class': 'mat-tab-nav-bar'},
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MdTabNav implements AfterContentInit, OnDestroy {
export class MdTabNav extends _MdTabNavMixinBase implements AfterContentInit, CanColor, OnDestroy {
/** Subject that emits when the component has been destroyed. */
private _onDestroy = new Subject<void>();

Expand All @@ -59,10 +69,29 @@ export class MdTabNav implements AfterContentInit, OnDestroy {
/** Subscription for window.resize event **/
private _resizeSubscription: Subscription;

constructor(
@Optional() private _dir: Directionality,
private _ngZone: NgZone,
private _changeDetectorRef: ChangeDetectorRef) { }
/** Background color of the tab nav. */
@Input()
get backgroundColor(): ThemePalette { return this._backgroundColor; }
set backgroundColor(value: ThemePalette) {
let nativeElement = this._elementRef.nativeElement;

this._renderer.removeClass(nativeElement, `mat-background-${this.backgroundColor}`);

if (value) {
this._renderer.addClass(nativeElement, `mat-background-${value}`);
}

this._backgroundColor = value;
}
private _backgroundColor: ThemePalette;

constructor(renderer: Renderer2,
elementRef: ElementRef,
@Optional() private _dir: Directionality,
private _ngZone: NgZone,
private _changeDetectorRef: ChangeDetectorRef) {
super(renderer, elementRef);
}

/** Notifies the component that the active link has been changed. */
updateActiveLink(element: ElementRef) {
Expand Down

0 comments on commit 374aaff

Please sign in to comment.