Skip to content

Commit e8e34bb

Browse files
committed
Create Expansion Panel.
1 parent 76faae5 commit e8e34bb

18 files changed

+584
-0
lines changed

src/demo-app/demo-app-module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {PlatformDemo} from './platform/platform-demo';
4343
import {AutocompleteDemo} from './autocomplete/autocomplete-demo';
4444
import {InputDemo} from './input/input-demo';
4545
import {StyleDemo} from './style/style-demo';
46+
import {ExpansionPanelDemo} from './expansion-panel/expansion-panel-demo';
4647

4748

4849
@NgModule({
@@ -100,6 +101,7 @@ import {StyleDemo} from './style/style-demo';
100101
RainyTabContent,
101102
FoggyTabContent,
102103
PlatformDemo,
104+
ExpansionPanelDemo,
103105
],
104106
providers: [
105107
{provide: OverlayContainer, useClass: FullscreenOverlayContainer}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export class DemoApp {
2626
{name: 'Chips', route: 'chips'},
2727
{name: 'Checkbox', route: 'checkbox'},
2828
{name: 'Dialog', route: 'dialog'},
29+
{name: 'Expansion Panel', route: 'expansion-panel'},
2930
{name: 'Gestures', route: 'gestures'},
3031
{name: 'Grid List', route: 'grid-list'},
3132
{name: 'Icon', route: 'icon'},

src/demo-app/demo-app/routes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {PlatformDemo} from '../platform/platform-demo';
3232
import {AutocompleteDemo} from '../autocomplete/autocomplete-demo';
3333
import {InputDemo} from '../input/input-demo';
3434
import {StyleDemo} from '../style/style-demo';
35+
import {ExpansionPanelDemo} from '../expansion-panel/expansion-panel-demo';
3536

3637
export const DEMO_APP_ROUTES: Routes = [
3738
{path: '', component: Home},
@@ -66,4 +67,5 @@ export const DEMO_APP_ROUTES: Routes = [
6667
{path: 'snack-bar', component: SnackBarDemo},
6768
{path: 'platform', component: PlatformDemo},
6869
{path: 'style', component: StyleDemo},
70+
{path: 'expansion-panel', component: ExpansionPanelDemo},
6971
];
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<h1>Single Expansion Panel</h1>
2+
<md-expansion-panel class="md-expansion-demo-width" #myPanel>
3+
<md-summary>
4+
<span title>{{ myPanel.expanded ? 'My Best Work' : 'Not My Best Work' }}</span>
5+
<span description *ngIf="myPanel.expanded">
6+
This is a description only shows while expanded.
7+
</span>
8+
</md-summary>
9+
This is the content text that makes sense here.
10+
<div md-action-row>
11+
<button md-button (click)="myPanel.expanded = false">CANCEL</button>
12+
<button md-button>SAVE</button>
13+
</div>
14+
</md-expansion-panel>
15+
<br>
16+
<h1>Expansion Panel Set</h1>
17+
<div>
18+
<p>Expansion Panel Options</p>
19+
<div>
20+
<md-slide-toggle [(ngModel)]="multiExpansion">Allow Multi Expansion</md-slide-toggle>
21+
<md-slide-toggle [(ngModel)]="showExpandIndicators">Show Indicators</md-slide-toggle>
22+
</div>
23+
<p>Expansion Panel Style</p>
24+
<md-radio-group [(ngModel)]="panelStyle">
25+
<md-radio-button value="default">Default</md-radio-button>
26+
<md-radio-button value="flat">Flat</md-radio-button>
27+
<md-radio-button value="wide">Wide</md-radio-button>
28+
</md-radio-group>
29+
<p>Expanded Panel(s)</p>
30+
<div>
31+
<md-checkbox [(ngModel)]="panel1.expanded">Panel 1</md-checkbox>
32+
<md-checkbox [(ngModel)]="panel2.expanded">Panel 2</md-checkbox>
33+
<md-checkbox [(ngModel)]="panel3.expanded">Panel 3</md-checkbox>
34+
</div>
35+
</div>
36+
<br>
37+
<md-expansion-panel-set [style]="panelStyle" [multi]="multiExpansion" class="md-expansion-demo-width">
38+
<md-expansion-panel #panel1>
39+
<md-summary [showExpandIndicator]="showExpandIndicators">section 1</md-summary>
40+
<p>This is the content text that makes sense here.</p>
41+
</md-expansion-panel>
42+
<md-expansion-panel #panel2>
43+
<md-summary [showExpandIndicator]="showExpandIndicators">section 2</md-summary>
44+
<p>This is the content text that makes sense here.</p>
45+
</md-expansion-panel>
46+
<md-expansion-panel #panel3>
47+
<md-summary [showExpandIndicator]="showExpandIndicators">section 3</md-summary>
48+
<md-checkbox #showButtons>Reveal Buttons Below</md-checkbox>
49+
<div md-action-row *ngIf="showButtons.checked">
50+
<button md-button (click)="panel2.expanded = true">OPEN SECTION 2</button>
51+
<button md-button (click)="panel3.expanded = false">CLOSE</button>
52+
</div>
53+
</md-expansion-panel>
54+
</md-expansion-panel-set>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.md-expansion-demo-width {
2+
width: 600px;
3+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import {Component, ViewEncapsulation} from '@angular/core';
2+
3+
@Component({
4+
moduleId: module.id,
5+
selector: 'expansion-panel-demo',
6+
styleUrls: ['expansion-panel-demo.css'],
7+
templateUrl: 'expansion-panel-demo.html',
8+
encapsulation: ViewEncapsulation.None,
9+
})
10+
export class ExpansionPanelDemo {
11+
panelStyle: string = 'default';
12+
multiExpansion: boolean = false;
13+
showExpandIndicators: boolean = true;
14+
}

src/lib/core/theming/_all-theme.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
@import '../../checkbox/checkbox-theme';
88
@import '../../chips/chips-theme';
99
@import '../../dialog/dialog-theme';
10+
@import '../../expansion-panel/expansion-panel-theme';
1011
@import '../../grid-list/grid-list-theme';
1112
@import '../../icon/icon-theme';
1213
@import '../../input/input-theme';
@@ -34,6 +35,7 @@
3435
@include mat-checkbox-theme($theme);
3536
@include mat-chips-theme($theme);
3637
@include mat-dialog-theme($theme);
38+
@include mat-expansion-panel-theme($theme);
3739
@include mat-grid-list-theme($theme);
3840
@include mat-icon-theme($theme);
3941
@include mat-input-theme($theme);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
@import '../core/theming/palette';
2+
@import '../core/theming/theming';
3+
4+
@mixin mat-expansion-panel-theme($theme) {
5+
$background: map-get($theme, background);
6+
$foreground: map-get($theme, foreground);
7+
8+
.mat-expansion-panel {
9+
background: mat-color($background, card);
10+
color: mat-color($foreground, base);
11+
}
12+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<ng-content select="md-summary"></ng-content>
2+
<div class="md-expansion-panel-body" [class.expanded]="expanded"
3+
[@bodyExpansion]="booleanToString(expanded)" [id]="getExpansionPanelId()">
4+
<ng-content></ng-content>
5+
<ng-content select="[md-action-row]"></ng-content>
6+
</div>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
@import '../core/style/variables';
2+
@import '../core/style/elevation';
3+
4+
.mat-expansion-panel-set {
5+
display: block;
6+
}
7+
8+
.mat-expansion-panel {
9+
@include mat-elevation-transition;
10+
box-sizing: content-box;
11+
display: block;
12+
13+
&:not(:first-child) {
14+
border-top: 1px solid rgba(0, 0, 0, 0.12);
15+
}
16+
17+
&:not([class*='mat-elevation-z']) {
18+
@include mat-elevation(2);
19+
}
20+
21+
&[wide='true'] {
22+
margin-left: 24px;
23+
margin-right: 24px;
24+
}
25+
}
26+
27+
div.md-expansion-panel-body {
28+
overflow: hidden;
29+
padding: 0 24px;
30+
}
31+
32+
[md-action-row] {
33+
border-top: 1px solid rgba(0, 0, 0, 0.12);
34+
display: flex;
35+
flex-direction: row;
36+
justify-content: flex-end;
37+
margin: 10px -24px 0 -24px;
38+
padding: 16px 8px 0 24px;
39+
40+
button.mat-button {
41+
margin-left: 8px;
42+
}
43+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import {async, TestBed} from '@angular/core/testing';
2+
import {Component} from '@angular/core';
3+
import {By} from '@angular/platform-browser';
4+
import {MdExpansionPanelModule, MdExpansionPanel} from './index';
5+
6+
7+
describe('MdExpansionPanel', () => {
8+
9+
beforeEach(async(() => {
10+
TestBed.configureTestingModule({
11+
imports: [MdExpansionPanelModule.forRoot()],
12+
declarations: [
13+
PanelWithContent
14+
],
15+
});
16+
17+
TestBed.compileComponents();
18+
}));
19+
20+
it('should apply expanded classes as appropriate', () => {
21+
let fixture = TestBed.createComponent(PanelWithContent);
22+
let bodyEl = fixture.debugElement.query(By.css('div.md-expansion-panel-body'));
23+
let summaryEl = fixture.debugElement.query(By.css('md-summary'));
24+
fixture.detectChanges();
25+
expect(summaryEl.nativeElement.classList).not.toContain('expanded');
26+
expect(bodyEl.nativeElement.classList).not.toContain('expanded');
27+
28+
fixture.componentInstance.expanded = true;
29+
fixture.detectChanges();
30+
expect(summaryEl.nativeElement.classList).toContain('expanded');
31+
expect(bodyEl.nativeElement.classList).toContain('expanded');
32+
});
33+
34+
it('emit correct events for change in panel expanded state', () => {
35+
let fixture = TestBed.createComponent(PanelWithContent);
36+
fixture.componentInstance.expanded = true;
37+
fixture.detectChanges();
38+
expect(fixture.componentInstance.openCallback).toHaveBeenCalled();
39+
expect(fixture.componentInstance.expandChangeCallback).toHaveBeenCalled();
40+
41+
fixture.componentInstance.expanded = false;
42+
fixture.detectChanges();
43+
expect(fixture.componentInstance.closeCallback).toHaveBeenCalled();
44+
expect(fixture.componentInstance.expandChangeCallback).toHaveBeenCalled();
45+
});
46+
47+
it('creates a unique panel id for each panel', () => {
48+
let fixtureOne = TestBed.createComponent(PanelWithContent);
49+
let summaryElOne = fixtureOne.debugElement.nativeElement.querySelector('md-summary');
50+
let fixtureTwo = TestBed.createComponent(PanelWithContent);
51+
let summaryElTwo = fixtureTwo.debugElement.nativeElement.querySelector('md-summary');
52+
fixtureOne.detectChanges();
53+
fixtureTwo.detectChanges();
54+
55+
let panelIdOne = summaryElOne.getAttribute('aria-controls');
56+
let panelIdTwo = summaryElTwo.getAttribute('aria-controls');
57+
expect(panelIdOne).not.toBe(panelIdTwo);
58+
});
59+
60+
});
61+
62+
describe('MdExpansionPanelSet', () => {
63+
64+
beforeEach(async(() => {
65+
TestBed.configureTestingModule({
66+
imports: [MdExpansionPanelModule.forRoot()],
67+
declarations: [
68+
SetOfPanels
69+
],
70+
});
71+
72+
TestBed.compileComponents();
73+
}));
74+
75+
it('should close all other panels upon a panel being opened', () => {
76+
let fixture = TestBed.createComponent(SetOfPanels);
77+
let panels = [].slice.call(
78+
fixture.debugElement.nativeElement.querySelectorAll('md-expansion-panel'));
79+
fixture.componentInstance.firstPanelExpanded = true;
80+
fixture.detectChanges();
81+
expect(panels.filter(panel => panel.classList.contains('expanded')).length).toBe(1);
82+
83+
fixture.componentInstance.secondPanelExpanded = true;
84+
fixture.detectChanges();
85+
expect(panels.filter(panel => panel.classList.contains('expanded')).length).toBe(1);
86+
});
87+
88+
it('should allow allow multiple panels to be open simultaneously', () => {
89+
let fixture = TestBed.createComponent(SetOfPanels);
90+
let panels = [].slice.call(
91+
fixture.debugElement.nativeElement.querySelectorAll('md-expansion-panel'));
92+
fixture.componentInstance.multi = true;
93+
fixture.componentInstance.firstPanelExpanded = true;
94+
fixture.componentInstance.secondPanelExpanded = true;
95+
fixture.detectChanges();
96+
expect(panels.filter(panel => panel.classList.contains('expanded')).length).toBe(2);
97+
});
98+
});
99+
100+
101+
102+
@Component({template: `
103+
<md-expansion-panel [expanded]="expanded"
104+
(open)="openCallback()"
105+
(expandChange)="expandChangeCallback()"
106+
(close)="closeCallback()">
107+
<md-summary>Panel Title</md-summary>
108+
<p>Some content</p>
109+
</md-expansion-panel>`})
110+
class PanelWithContent {
111+
expanded: boolean = false;
112+
openCallback = jasmine.createSpy('openCallback');
113+
closeCallback = jasmine.createSpy('closeCallback');
114+
expandChangeCallback = jasmine.createSpy('expandChangeCallback');
115+
testPanel: MdExpansionPanel;
116+
}
117+
118+
119+
@Component({template: `
120+
<md-expansion-panel-set [style]="style"
121+
[multi]="multi">
122+
<md-expansion-panel [expanded]="firstPanelExpanded">
123+
<md-summary>Summary</md-summary>
124+
<p>Content</p>
125+
</md-expansion-panel>
126+
<md-expansion-panel [expanded]="secondPanelExpanded">
127+
<md-summary>Summary</md-summary>
128+
<p>Content</p>
129+
</md-expansion-panel>
130+
<md-expansion-panel [expanded]="thirdPanelExpanded">
131+
<md-summary>Summary</md-summary>
132+
<p>Content</p>
133+
</md-expansion-panel>
134+
</md-expansion-panel-set>`})
135+
class SetOfPanels {
136+
style: string = 'default';
137+
multi: boolean = false;
138+
firstPanelExpanded: boolean = false;
139+
secondPanelExpanded: boolean = false;
140+
thirdPanelExpanded: boolean = false;
141+
}

0 commit comments

Comments
 (0)