Skip to content

Commit a494c92

Browse files
crisbetommalerba
authored andcommitted
feat(tabs): add the ability to invert the header (#2391)
Adds the ability to set the tab header position to the bottom. This inverts the tabs and the ink bar. Fixes #2387.
1 parent 15eb33a commit a494c92

File tree

6 files changed

+53
-6
lines changed

6 files changed

+53
-6
lines changed

Diff for: src/demo-app/tabs/tabs-demo.html

+10
Original file line numberDiff line numberDiff line change
@@ -210,3 +210,13 @@ <h1>Tabs with simplified api</h1>
210210
This tab is about combustion!
211211
</md-tab>
212212
</md-tab-group>
213+
214+
<h1>Inverted tabs</h1>
215+
<md-tab-group class="demo-tab-group" headerPosition="below">
216+
<md-tab label="Earth">
217+
This tab is about the Earth!
218+
</md-tab>
219+
<md-tab label="Fire">
220+
This tab is about combustion!
221+
</md-tab>
222+
</md-tab-group>

Diff for: src/lib/tabs/_tabs-common.scss

+5
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,9 @@ $md-tab-animation-duration: 500ms !default;
3939
bottom: 0;
4040
height: 2px;
4141
transition: $md-tab-animation-duration $ease-in-out-curve-function;
42+
43+
.md-tab-group-inverted-header & {
44+
bottom: auto;
45+
top: 0;
46+
}
4247
}

Diff for: src/lib/tabs/_tabs-theme.scss

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
@import '../core/theming/palette';
22
@import '../core/theming/theming';
33

4-
54
@mixin md-tabs-theme($theme) {
65
$primary: map-get($theme, primary);
76
$accent: map-get($theme, accent);
87
$warn: map-get($theme, warn);
98
$background: map-get($theme, background);
109
$foreground: map-get($theme, foreground);
10+
$header-border: 1px solid md-color($background, status-bar);
1111

1212
[md-tab-nav-bar],
1313
.md-tab-header {
14-
border-bottom: 1px solid md-color($background, status-bar);
14+
border-bottom: $header-border;
15+
16+
.md-tab-group-inverted-header & {
17+
border-top: $header-border;
18+
border-bottom: none;
19+
}
1520
}
16-
21+
1722
.md-tab-label:focus {
1823
background-color: md-color($primary, 100, 0.3);
1924
}
20-
25+
2126
md-ink-bar {
2227
background-color: md-color($primary, 500);
2328
}

Diff for: src/lib/tabs/tab-group.scss

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
display: flex;
77
flex-direction: column;
88
font-family: $md-font-family;
9+
10+
&.md-tab-group-inverted-header {
11+
flex-direction: column-reverse;
12+
}
913
}
1014

1115
// Wraps each tab label

Diff for: src/lib/tabs/tab-group.spec.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {
22
async, fakeAsync, tick, ComponentFixture, TestBed
33
} from '@angular/core/testing';
4-
import {MdTabGroup, MdTabsModule} from './tab-group';
4+
import {MdTabGroup, MdTabsModule, MdTabHeaderPosition} from './tab-group';
55
import {Component, ViewChild} from '@angular/core';
66
import {By} from '@angular/platform-browser';
77
import {Observable} from 'rxjs/Observable';
@@ -247,6 +247,17 @@ describe('MdTabGroup', () => {
247247
it('should support @ViewChild in the tab content', () => {
248248
expect(fixture.componentInstance.legumes).toBeTruthy();
249249
});
250+
251+
it('should support setting the header position', () => {
252+
let tabGroupNode = fixture.debugElement.query(By.css('md-tab-group')).nativeElement;
253+
254+
expect(tabGroupNode.classList).not.toContain('md-tab-group-inverted-header');
255+
256+
tabGroup.headerPosition = 'below';
257+
fixture.detectChanges();
258+
259+
expect(tabGroupNode.classList).toContain('md-tab-group-inverted-header');
260+
});
250261
});
251262

252263
/**
@@ -282,6 +293,7 @@ describe('MdTabGroup', () => {
282293
template: `
283294
<md-tab-group class="tab-group"
284295
[(selectedIndex)]="selectedIndex"
296+
[headerPosition]="headerPosition"
285297
(focusChange)="handleFocus($event)"
286298
(selectChange)="handleSelection($event)">
287299
<md-tab>
@@ -303,6 +315,7 @@ class SimpleTabsTestApp {
303315
selectedIndex: number = 1;
304316
focusEvent: any;
305317
selectEvent: any;
318+
headerPosition: MdTabHeaderPosition = 'above';
306319
handleFocus(event: any) {
307320
this.focusEvent = event;
308321
}

Diff for: src/lib/tabs/tab-group.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ export class MdTabChangeEvent {
3939
tab: MdTab;
4040
}
4141

42+
/** Possible positions for the tab header. */
43+
export type MdTabHeaderPosition = 'above' | 'below';
44+
4245
/**
4346
* Material design tab-group component. Supports basic tab pairs (label + content) and includes
4447
* animated ink-bar, keyboard navigation, and screen reader.
@@ -49,7 +52,10 @@ export class MdTabChangeEvent {
4952
selector: 'md-tab-group',
5053
templateUrl: 'tab-group.html',
5154
styleUrls: ['tab-group.css'],
52-
host: { '[class.md-tab-group-dynamic-height]': 'dynamicHeight' }
55+
host: {
56+
'[class.md-tab-group-dynamic-height]': 'dynamicHeight',
57+
'[class.md-tab-group-inverted-header]': 'headerPosition === "below"',
58+
}
5359
})
5460
export class MdTabGroup {
5561
@ContentChildren(MdTab) _tabs: QueryList<MdTab>;
@@ -83,6 +89,10 @@ export class MdTabGroup {
8389
set selectedIndex(value: number) { this._indexToSelect = value; }
8490
get selectedIndex(): number { return this._selectedIndex; }
8591

92+
/** Position of the tab header. */
93+
@Input()
94+
headerPosition: MdTabHeaderPosition = 'above';
95+
8696
/** Output to enable support for two-way binding on `selectedIndex`. */
8797
@Output() get selectedIndexChange(): Observable<number> {
8898
return this.selectChange.map(event => event.index);

0 commit comments

Comments
 (0)