Skip to content

Commit fb71eb1

Browse files
committed
feat(list): add list component
1 parent a61e2e9 commit fb71eb1

File tree

13 files changed

+553
-1
lines changed

13 files changed

+553
-1
lines changed
24.4 KB
Loading
24.5 KB
Loading

scripts/e2e.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ export LOGS_DIR=/tmp/angular-material2-build/logs
55
export SAUCE_USERNAME=angular-ci
66
export SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
77
export TRAVIS_JOB_NUMBER=12345
8+
export BROWSER_PROVIDER_READY_FILE=/tmp/angular-material2-build/readyfile
9+
810

911
mkdir -p $LOGS_DIR
1012
rm -f $BROWSER_PROVIDER_READY_FILE

src/components/list/list-item.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div class="md-list-item">
2+
<ng-content select="[md-list-avatar]"></ng-content>
3+
<div class="md-list-text"><ng-content select="[md-line]"></ng-content></div>
4+
<ng-content></ng-content>
5+
</div>

src/components/list/list.scss

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
@import "variables";
2+
3+
$md-list-side-padding: 16px;
4+
$md-list-avatar-size: 40px;
5+
6+
/* Normal list variables */
7+
$md-list-top-padding: 8px;
8+
$md-list-font-size: 16px;
9+
$md-list-secondary-font: 14px;
10+
// height for single-line lists
11+
$md-list-base-height: 48px;
12+
// height for single-line lists with avatars
13+
$md-list-avatar-height: 56px;
14+
// spec requires two- and three-line lists be taller
15+
$md-list-two-line-height: 72px;
16+
$md-list-three-line-height: 88px;
17+
18+
/* Dense list variables */
19+
$md-dense-top-padding: 4px;
20+
$md-dense-font-size: 13px;
21+
$md-dense-base-height: 40px;
22+
$md-dense-avatar-height: 48px;
23+
$md-dense-two-line-height: 60px;
24+
$md-dense-three-line-height: 76px;
25+
26+
/*
27+
This mixin provides all list-item styles, changing font size and height
28+
based on whether the list is in "dense" mode.
29+
*/
30+
@mixin md-list-item-base($font-size, $base-height, $avatar-height,
31+
$two-line-height, $three-line-height) {
32+
33+
.md-list-item {
34+
display: flex;
35+
flex-direction: row;
36+
align-items: center;
37+
font-family: $md-font-family;
38+
box-sizing: border-box;
39+
font-size: $font-size;
40+
height: $base-height;
41+
padding: 0 $md-list-side-padding;
42+
}
43+
44+
&.md-list-avatar .md-list-item {
45+
height: $avatar-height;
46+
}
47+
48+
&.md-2-line .md-list-item {
49+
height: $two-line-height;
50+
}
51+
52+
&.md-3-line .md-list-item {
53+
height: $three-line-height;
54+
}
55+
56+
.md-list-text {
57+
display: flex;
58+
flex-direction: column;
59+
width: 100%;
60+
padding: 0 $md-list-side-padding;
61+
62+
&:first-child {
63+
padding: 0;
64+
}
65+
66+
&:empty {
67+
display: none;
68+
}
69+
70+
& > * {
71+
margin: 0;
72+
padding: 0;
73+
font-weight: normal;
74+
font-size: inherit;
75+
}
76+
}
77+
78+
[md-list-avatar] {
79+
width: $md-list-avatar-size;
80+
height: $md-list-avatar-size;
81+
}
82+
}
83+
84+
/*
85+
This mixin provides all md-line styles, changing secondary font size
86+
based on whether the list is in "dense" mode.
87+
*/
88+
@mixin md-line-base($secondary-font-size) {
89+
90+
[md-line] {
91+
display: block;
92+
white-space: nowrap;
93+
overflow-x: hidden;
94+
text-overflow: ellipsis;
95+
box-sizing: border-box;
96+
97+
// all lines but the top line should have smaller text
98+
&:nth-child(n+2) {
99+
font-size: $secondary-font-size;
100+
}
101+
}
102+
}
103+
104+
md-list {
105+
padding-top: $md-list-top-padding;
106+
display: block;
107+
108+
md-list-item {
109+
@include md-list-item-base(
110+
$md-list-font-size,
111+
$md-list-base-height,
112+
$md-list-avatar-height,
113+
$md-list-two-line-height,
114+
$md-list-three-line-height
115+
);
116+
117+
@include md-line-base($md-list-secondary-font);
118+
}
119+
}
120+
121+
122+
md-list[dense] {
123+
padding-top: $md-dense-top-padding;
124+
display: block;
125+
126+
127+
md-list-item {
128+
@include md-list-item-base(
129+
$md-dense-font-size,
130+
$md-dense-base-height,
131+
$md-dense-avatar-height,
132+
$md-dense-two-line-height,
133+
$md-dense-three-line-height
134+
);
135+
136+
@include md-line-base($md-dense-font-size);
137+
}
138+
}

src/components/list/list.spec.ts

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import {
2+
inject,
3+
TestComponentBuilder
4+
} from 'angular2/testing';
5+
import {
6+
it,
7+
describe,
8+
expect,
9+
beforeEach,
10+
} from '../../core/facade/testing';
11+
import {Component} from 'angular2/core';
12+
import {By} from 'angular2/platform/browser';
13+
14+
import {MD_LIST_DIRECTIVES} from './list';
15+
16+
export function main() {
17+
describe('MdList', () => {
18+
let builder: TestComponentBuilder;
19+
20+
beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
21+
builder = tcb;
22+
}));
23+
24+
it('should not apply any class to a list without lines', (done: () => void) => {
25+
var template = `
26+
<md-list>
27+
<md-list-item>
28+
Paprika
29+
</md-list-item>
30+
</md-list>
31+
`;
32+
return builder.overrideTemplate(TestList, template)
33+
.createAsync(TestList).then((fixture) => {
34+
let listItem = fixture.debugElement.query(By.css('md-list-item'));
35+
fixture.detectChanges();
36+
expect(listItem.nativeElement.className).toBe('');
37+
done();
38+
});
39+
});
40+
41+
it('should apply md-2-line class to lists with two lines', (done: () => void) => {
42+
var template = `
43+
<md-list>
44+
<md-list-item *ngFor="#item of items">
45+
<img src="">
46+
<h3 md-line>{{item.name}}</h3>
47+
<p md-line>{{item.description}}</p>
48+
</md-list-item>
49+
</md-list>
50+
`;
51+
return builder.overrideTemplate(TestList, template)
52+
.createAsync(TestList).then((fixture) => {
53+
fixture.detectChanges();
54+
let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item'));
55+
expect(listItems[0].nativeElement.className).toBe('md-2-line');
56+
expect(listItems[1].nativeElement.className).toBe('md-2-line');
57+
done();
58+
});
59+
});
60+
61+
it('should apply md-3-line class to lists with three lines', (done: () => void) => {
62+
var template = `
63+
<md-list>
64+
<md-list-item *ngFor="#item of items">
65+
<h3 md-line>{{item.name}}</h3>
66+
<p md-line>{{item.description}}</p>
67+
<p md-line>Some other text</p>
68+
</md-list-item>
69+
</md-list>
70+
`;
71+
return builder.overrideTemplate(TestList, template)
72+
.createAsync(TestList).then((fixture) => {
73+
fixture.detectChanges();
74+
let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item'));
75+
expect(listItems[0].nativeElement.className).toBe('md-3-line');
76+
expect(listItems[1].nativeElement.className).toBe('md-3-line');
77+
done();
78+
});
79+
});
80+
81+
it('should apply md-list-avatar class to list items with avatars', (done: () => void) => {
82+
var template = `
83+
<md-list>
84+
<md-list-item>
85+
<img src="" md-list-avatar>
86+
Paprika
87+
</md-list-item>
88+
<md-list-item>
89+
Pepper
90+
</md-list-item>
91+
</md-list>
92+
`;
93+
return builder.overrideTemplate(TestList, template)
94+
.createAsync(TestList).then((fixture) => {
95+
fixture.detectChanges();
96+
let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item'));
97+
expect(listItems[0].nativeElement.className).toBe('md-list-avatar');
98+
expect(listItems[1].nativeElement.className).toBe('');
99+
done();
100+
});
101+
});
102+
103+
it('should not clear custom classes provided by user', (done: () => void) => {
104+
var template = `
105+
<md-list>
106+
<md-list-item class="test-class" *ngFor="#item of items">
107+
<h3 md-line>{{item.name}}</h3>
108+
<p md-line>{{item.description}}</p>
109+
</md-list-item>
110+
</md-list>
111+
`;
112+
return builder.overrideTemplate(TestList, template)
113+
.createAsync(TestList).then((fixture) => {
114+
fixture.detectChanges();
115+
let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item'));
116+
expect(listItems[0].nativeElement.classList.contains('test-class')).toBe(true);
117+
done();
118+
});
119+
});
120+
121+
it('should update classes if number of lines change', (done: () => void) => {
122+
var template = `
123+
<md-list>
124+
<md-list-item *ngFor="#item of items">
125+
<h3 md-line>{{item.name}}</h3>
126+
<p md-line>{{item.description}}</p>
127+
<p md-line *ngIf="showThirdLine">Some other text</p>
128+
</md-list-item>
129+
</md-list>
130+
`;
131+
return builder.overrideTemplate(TestList, template)
132+
.createAsync(TestList).then((fixture) => {
133+
fixture.debugElement.componentInstance.showThirdLine = false;
134+
fixture.detectChanges();
135+
let listItem = fixture.debugElement.children[0].query(By.css('md-list-item'));
136+
expect(listItem.nativeElement.className).toBe('md-2-line');
137+
138+
fixture.debugElement.componentInstance.showThirdLine = true;
139+
fixture.detectChanges();
140+
setTimeout(() => {
141+
expect(listItem.nativeElement.className).toBe('md-3-line');
142+
done();
143+
});
144+
});
145+
});
146+
147+
it('should add aria roles properly', (done: () => void) => {
148+
var template = `
149+
<md-list>
150+
<md-list-item *ngFor="#item of items">
151+
{{item.name}}
152+
</md-list-item>
153+
</md-list>
154+
`;
155+
return builder.overrideTemplate(TestList, template)
156+
.createAsync(TestList).then((fixture) => {
157+
fixture.detectChanges();
158+
let list = fixture.debugElement.children[0];
159+
let listItem = fixture.debugElement.children[0].query(By.css('md-list-item'));
160+
expect(list.nativeElement.getAttribute('role')).toBe('list');
161+
expect(listItem.nativeElement.getAttribute('role')).toBe('listitem');
162+
done();
163+
});
164+
});
165+
166+
});
167+
}
168+
169+
@Component({
170+
selector: 'test-list',
171+
template: ``,
172+
directives: [MD_LIST_DIRECTIVES]
173+
})
174+
class TestList {
175+
items: any[] = [
176+
{'name': 'Paprika', 'description': 'A seasoning'},
177+
{'name': 'Pepper', 'description': 'Another seasoning'}
178+
];
179+
showThirdLine: boolean = false;
180+
}

0 commit comments

Comments
 (0)