Skip to content

Commit f6944e4

Browse files
andrewseguinjelbourn
authored andcommitted
feat(tabs): animate tab change, include optional dynamic height (#1788)
1 parent 716372b commit f6944e4

File tree

15 files changed

+416
-111
lines changed

15 files changed

+416
-111
lines changed

e2e/components/tabs/tabs.e2e.ts

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,17 @@ describe('tabs', () => {
1111
browser.get('/tabs');
1212
tabGroup = element(by.css('md-tab-group'));
1313
tabLabels = element.all(by.css('.md-tab-label'));
14-
tabBodies = element.all(by.css('.md-tab-body'));
14+
tabBodies = element.all(by.css('md-tab-body'));
1515
});
1616

1717
it('should change tabs when the label is clicked', () => {
1818
tabLabels.get(1).click();
19-
expect(getActiveStates(tabLabels)).toEqual([false, true, false]);
20-
expect(getActiveStates(tabBodies)).toEqual([false, true, false]);
19+
expect(getLabelActiveStates(tabLabels)).toEqual([false, true, false]);
20+
expect(getBodyActiveStates(tabBodies)).toEqual([false, true, false]);
2121

2222
tabLabels.get(0).click();
23-
expect(getActiveStates(tabLabels)).toEqual([true, false, false]);
24-
expect(getActiveStates(tabBodies)).toEqual([true, false, false]);
23+
expect(getLabelActiveStates(tabLabels)).toEqual([true, false, false]);
24+
expect(getBodyActiveStates(tabBodies)).toEqual([true, false, false]);
2525
});
2626

2727
it('should change focus with keyboard interaction', () => {
@@ -49,18 +49,13 @@ describe('tabs', () => {
4949
});
5050
});
5151

52-
/**
53-
* A helper function to perform the sendKey action
54-
* @param key
55-
*/
52+
/** A helper function to perform the sendKey action. */
5653
function pressKey(key: string) {
5754
browser.actions().sendKeys(key).perform();
5855
}
5956

6057
/**
61-
* Returns an array of true/false that represents the focus states of the provided elements
62-
* @param elements
63-
* @returns {webdriver.promise.Promise<Promise<boolean>[]>|webdriver.promise.Promise<T[]>}
58+
* Returns an array of true/false that represents the focus states of the provided elements.
6459
*/
6560
function getFocusStates(elements: ElementArrayFinder) {
6661
return elements.map(element => {
@@ -72,21 +67,19 @@ function getFocusStates(elements: ElementArrayFinder) {
7267
});
7368
}
7469

75-
/**
76-
* Returns an array of true/false that represents the active states for the provided elements
77-
* @param elements
78-
* @returns {webdriver.promise.Promise<Promise<boolean>[]>|webdriver.promise.Promise<T[]>}
79-
*/
80-
function getActiveStates(elements: ElementArrayFinder) {
81-
return getClassStates(elements, 'md-tab-active');
70+
/** Returns an array of true/false that represents the active states for the provided elements. */
71+
function getLabelActiveStates(elements: ElementArrayFinder) {
72+
return getClassStates(elements, 'md-tab-label-active');
73+
}
74+
75+
/** Returns an array of true/false that represents the active states for the provided elements */
76+
function getBodyActiveStates(elements: ElementArrayFinder) {
77+
return getClassStates(elements, 'md-tab-body-active');
8278
}
8379

8480
/**
8581
* Returns an array of true/false values that represents whether the provided className is on
86-
* each element
87-
* @param elements
88-
* @param className
89-
* @returns {webdriver.promise.Promise<Promise<boolean>[]>|webdriver.promise.Promise<T[]>}
82+
* each element.
9083
*/
9184
function getClassStates(elements: ElementArrayFinder, className: string) {
9285
return elements.map(element => {

src/demo-app/tabs/tabs-demo.html

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,84 @@ <h1>Tab Nav Bar</h1>
1414
</div>
1515

1616

17-
<h1>Tab Group Demo</h1>
17+
<h1>Tab Group Demo - Dynamic Height</h1>
1818

19-
<md-tab-group class="demo-tab-group">
20-
<md-tab *ngFor="let tab of tabs; let i = index" [disabled]="i == 1">
19+
<md-tab-group class="demo-tab-group" md-dynamic-height>
20+
<md-tab *ngFor="let tab of tabs" [disabled]="tab.disabled">
21+
<template md-tab-label>{{tab.label}}</template>
22+
{{tab.content}}
23+
<br>
24+
<br>
25+
<div *ngIf="tab.extraContent">
26+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue.
27+
Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus.
28+
In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec,
29+
feugiat ultricies mi. Aliquam erat volutpat. Nam placerat, tortor in ultrices porttitor,
30+
orci enim rutrum enim, vel tempor sapien arcu a tellus. Vivamus convallis sodales ante varius
31+
gravida. Curabitur a purus vel augue ultrices ultricies id a nisl. Nullam malesuada consequat
32+
diam, a facilisis tortor volutpat et. Sed urna dolor, aliquet vitae posuere vulputate, euismod
33+
ac lorem. Sed felis risus, pulvinar at interdum quis, vehicula sed odio. Phasellus in enim
34+
venenatis, iaculis tortor eu, bibendum ante. Donec ac tellus dictum neque volutpat blandit.
35+
Praesent efficitur faucibus risus, ac auctor purus porttitor vitae. Phasellus ornare dui nec
36+
orci posuere, nec luctus mauris semper.
37+
<br>
38+
<br>
39+
Morbi viverra, ante vel aliquet tincidunt, leo dolor pharetra quam, at semper massa orci nec
40+
magna. Donec posuere nec sapien sed laoreet. Etiam cursus nunc in condimentum facilisis.
41+
Etiam in tempor tortor. Vivamus faucibus egestas enim, at convallis diam pulvinar vel.
42+
Cras ac orci eget nisi maximus cursus. Nunc urna libero, viverra sit amet nisl at, hendrerit
43+
tempor turpis. Maecenas facilisis convallis mi vel tempor. Nullam vitae nunc leo. Cras sed
44+
nisl consectetur, rhoncus sapien sit amet, tempus sapien.
45+
<br>
46+
<br>
47+
Integer turpis erat, porttitor vitae mi faucibus, laoreet interdum tellus. Curabitur posuere
48+
molestie dictum. Morbi eget congue risus, quis rhoncus quam. Suspendisse vitae hendrerit erat,
49+
at posuere mi. Cras eu fermentum nunc. Sed id ante eu orci commodo volutpat non ac est.
50+
Praesent ligula diam, congue eu enim scelerisque, finibus commodo lectus.
51+
</div>
52+
<br>
53+
<br>
54+
<md-input placeholder="Tab Label" [(ngModel)]="tab.label"></md-input>
55+
</md-tab>
56+
</md-tab-group>
57+
58+
59+
<h1>Tab Group Demo - Fixed Height</h1>
60+
61+
<md-tab-group class="demo-tab-group" style="height: 200px">
62+
<md-tab *ngFor="let tab of tabs" [disabled]="tab.disabled">
2163
<template md-tab-label>{{tab.label}}</template>
2264
{{tab.content}}
2365
<br>
2466
<br>
67+
<div *ngIf="tab.extraContent">
68+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla venenatis ante augue.
69+
Phasellus volutpat neque ac dui mattis vulputate. Etiam consequat aliquam cursus.
70+
In sodales pretium ultrices. Maecenas lectus est, sollicitudin consectetur felis nec,
71+
feugiat ultricies mi. Aliquam erat volutpat. Nam placerat, tortor in ultrices porttitor,
72+
orci enim rutrum enim, vel tempor sapien arcu a tellus. Vivamus convallis sodales ante varius
73+
gravida. Curabitur a purus vel augue ultrices ultricies id a nisl. Nullam malesuada consequat
74+
diam, a facilisis tortor volutpat et. Sed urna dolor, aliquet vitae posuere vulputate, euismod
75+
ac lorem. Sed felis risus, pulvinar at interdum quis, vehicula sed odio. Phasellus in enim
76+
venenatis, iaculis tortor eu, bibendum ante. Donec ac tellus dictum neque volutpat blandit.
77+
Praesent efficitur faucibus risus, ac auctor purus porttitor vitae. Phasellus ornare dui nec
78+
orci posuere, nec luctus mauris semper.
79+
<br>
80+
<br>
81+
Morbi viverra, ante vel aliquet tincidunt, leo dolor pharetra quam, at semper massa orci nec
82+
magna. Donec posuere nec sapien sed laoreet. Etiam cursus nunc in condimentum facilisis.
83+
Etiam in tempor tortor. Vivamus faucibus egestas enim, at convallis diam pulvinar vel.
84+
Cras ac orci eget nisi maximus cursus. Nunc urna libero, viverra sit amet nisl at, hendrerit
85+
tempor turpis. Maecenas facilisis convallis mi vel tempor. Nullam vitae nunc leo. Cras sed
86+
nisl consectetur, rhoncus sapien sit amet, tempus sapien.
87+
<br>
88+
<br>
89+
Integer turpis erat, porttitor vitae mi faucibus, laoreet interdum tellus. Curabitur posuere
90+
molestie dictum. Morbi eget congue risus, quis rhoncus quam. Suspendisse vitae hendrerit erat,
91+
at posuere mi. Cras eu fermentum nunc. Sed id ante eu orci commodo volutpat non ac est.
92+
Praesent ligula diam, congue eu enim scelerisque, finibus commodo lectus.
93+
</div>
94+
<br>
2595
<br>
2696
<md-input placeholder="Tab Label" [(ngModel)]="tab.label"></md-input>
2797
</md-tab>

src/demo-app/tabs/tabs-demo.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
.md-tab-header {
1717
background: #f9f9f9;
1818
}
19-
.md-tab-body {
19+
.md-tab-body-content {
2020
padding: 12px;
2121
}
2222
}

src/demo-app/tabs/tabs-demo.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,21 @@ export class TabsDemo {
1818
activeLinkIndex = 0;
1919

2020
tabs = [
21-
{label: 'Tab One', content: 'This is the body of the first tab'},
22-
{label: 'Tab Two', content: 'This is the body of the second tab'},
23-
{label: 'Tab Three', content: 'This is the body of the third tab'},
21+
{
22+
label: 'Tab One',
23+
content: 'This is the body of the first tab'},
24+
{
25+
label: 'Tab Two',
26+
disabled: true,
27+
content: 'This is the body of the second tab'},
28+
{
29+
label: 'Tab Three',
30+
extraContent: true,
31+
content: 'This is the body of the third tab'},
32+
{
33+
label: 'Tab Four',
34+
content: 'This is the body of the fourth tab'
35+
},
2436
];
2537

2638
asyncTabs: Observable<any>;

src/lib/core/portal/portal-directives.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,9 @@ export class PortalHostDirective extends BasePortalHost implements OnDestroy {
5757
}
5858

5959
set portal(p: Portal<any>) {
60-
this._replaceAttachedPortal(p);
60+
if (p) {
61+
this._replaceAttachedPortal(p);
62+
}
6163
}
6264

6365
ngOnDestroy() {
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This mixin ensures an element spans to fill the nearest ancestor with defined positioning.
2+
@mixin md-fill {
3+
position: absolute;
4+
top: 0;
5+
left: 0;
6+
right: 0;
7+
bottom: 0;
8+
}

src/lib/core/style/_sidenav-common.scss

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/lib/menu/menu.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// TODO(kara): animation for menu opening
33

44
@import '../core/style/button-common';
5-
@import '../core/style/sidenav-common';
5+
@import '../core/style/layout-common';
66
@import '../core/style/menu-common';
77

88
$md-menu-vertical-padding: 8px !default;

src/lib/sidenav/sidenav.scss

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@import '../core/style/variables';
22
@import '../core/style/elevation';
3-
@import '../core/style/sidenav-common';
3+
@import '../core/style/layout-common';
44

55

66
// Mixin to help with defining LTR/RTL 'transform: translate3d()' values.
@@ -57,7 +57,7 @@ md-sidenav-layout {
5757

5858
// TODO(hansl): Update this with a more robust solution.
5959
&[fullscreen] {
60-
@include md-fullscreen();
60+
@include md-fill();
6161

6262
&.md-sidenav-opened {
6363
overflow: hidden;
@@ -66,7 +66,7 @@ md-sidenav-layout {
6666
}
6767

6868
.md-sidenav-backdrop {
69-
@include md-fullscreen();
69+
@include md-fill();
7070

7171
display: block;
7272

src/lib/tabs/_tabs-common.scss

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
$md-tab-bar-height: 48px !default;
44

5+
$md-tab-animation-duration: 500ms !default;
6+
57
// Mixin styles for labels that are contained within the tab header.
68
@mixin tab-label {
79
line-height: $md-tab-bar-height;
@@ -36,5 +38,5 @@ $md-tab-bar-height: 48px !default;
3638
position: absolute;
3739
bottom: 0;
3840
height: 2px;
39-
transition: 350ms ease-out;
40-
}
41+
transition: $md-tab-animation-duration $ease-in-out-curve-function;
42+
}

0 commit comments

Comments
 (0)