Skip to content

Commit

Permalink
feat(list): add list component
Browse files Browse the repository at this point in the history
  • Loading branch information
kara committed Mar 21, 2016
1 parent a61e2e9 commit fb71eb1
Show file tree
Hide file tree
Showing 13 changed files with 553 additions and 1 deletion.
Binary file modified screenshots/demo page: index.screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added screenshots/initial state.screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions scripts/e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export LOGS_DIR=/tmp/angular-material2-build/logs
export SAUCE_USERNAME=angular-ci
export SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
export TRAVIS_JOB_NUMBER=12345
export BROWSER_PROVIDER_READY_FILE=/tmp/angular-material2-build/readyfile


mkdir -p $LOGS_DIR
rm -f $BROWSER_PROVIDER_READY_FILE
Expand Down
5 changes: 5 additions & 0 deletions src/components/list/list-item.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<div class="md-list-item">
<ng-content select="[md-list-avatar]"></ng-content>
<div class="md-list-text"><ng-content select="[md-line]"></ng-content></div>
<ng-content></ng-content>
</div>
138 changes: 138 additions & 0 deletions src/components/list/list.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
@import "variables";

$md-list-side-padding: 16px;
$md-list-avatar-size: 40px;

/* Normal list variables */
$md-list-top-padding: 8px;
$md-list-font-size: 16px;
$md-list-secondary-font: 14px;
// height for single-line lists
$md-list-base-height: 48px;
// height for single-line lists with avatars
$md-list-avatar-height: 56px;
// spec requires two- and three-line lists be taller
$md-list-two-line-height: 72px;
$md-list-three-line-height: 88px;

/* Dense list variables */
$md-dense-top-padding: 4px;
$md-dense-font-size: 13px;
$md-dense-base-height: 40px;
$md-dense-avatar-height: 48px;
$md-dense-two-line-height: 60px;
$md-dense-three-line-height: 76px;

/*
This mixin provides all list-item styles, changing font size and height
based on whether the list is in "dense" mode.
*/
@mixin md-list-item-base($font-size, $base-height, $avatar-height,
$two-line-height, $three-line-height) {

.md-list-item {
display: flex;
flex-direction: row;
align-items: center;
font-family: $md-font-family;
box-sizing: border-box;
font-size: $font-size;
height: $base-height;
padding: 0 $md-list-side-padding;
}

&.md-list-avatar .md-list-item {
height: $avatar-height;
}

&.md-2-line .md-list-item {
height: $two-line-height;
}

&.md-3-line .md-list-item {
height: $three-line-height;
}

.md-list-text {
display: flex;
flex-direction: column;
width: 100%;
padding: 0 $md-list-side-padding;

&:first-child {
padding: 0;
}

&:empty {
display: none;
}

& > * {
margin: 0;
padding: 0;
font-weight: normal;
font-size: inherit;
}
}

[md-list-avatar] {
width: $md-list-avatar-size;
height: $md-list-avatar-size;
}
}

/*
This mixin provides all md-line styles, changing secondary font size
based on whether the list is in "dense" mode.
*/
@mixin md-line-base($secondary-font-size) {

[md-line] {
display: block;
white-space: nowrap;
overflow-x: hidden;
text-overflow: ellipsis;
box-sizing: border-box;

// all lines but the top line should have smaller text
&:nth-child(n+2) {
font-size: $secondary-font-size;
}
}
}

md-list {
padding-top: $md-list-top-padding;
display: block;

md-list-item {
@include md-list-item-base(
$md-list-font-size,
$md-list-base-height,
$md-list-avatar-height,
$md-list-two-line-height,
$md-list-three-line-height
);

@include md-line-base($md-list-secondary-font);
}
}


md-list[dense] {
padding-top: $md-dense-top-padding;
display: block;


md-list-item {
@include md-list-item-base(
$md-dense-font-size,
$md-dense-base-height,
$md-dense-avatar-height,
$md-dense-two-line-height,
$md-dense-three-line-height
);

@include md-line-base($md-dense-font-size);
}
}
180 changes: 180 additions & 0 deletions src/components/list/list.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import {
inject,
TestComponentBuilder
} from 'angular2/testing';
import {
it,
describe,
expect,
beforeEach,
} from '../../core/facade/testing';
import {Component} from 'angular2/core';
import {By} from 'angular2/platform/browser';

import {MD_LIST_DIRECTIVES} from './list';

export function main() {
describe('MdList', () => {
let builder: TestComponentBuilder;

beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
builder = tcb;
}));

it('should not apply any class to a list without lines', (done: () => void) => {
var template = `
<md-list>
<md-list-item>
Paprika
</md-list-item>
</md-list>
`;
return builder.overrideTemplate(TestList, template)
.createAsync(TestList).then((fixture) => {
let listItem = fixture.debugElement.query(By.css('md-list-item'));
fixture.detectChanges();
expect(listItem.nativeElement.className).toBe('');
done();
});
});

it('should apply md-2-line class to lists with two lines', (done: () => void) => {
var template = `
<md-list>
<md-list-item *ngFor="#item of items">
<img src="">
<h3 md-line>{{item.name}}</h3>
<p md-line>{{item.description}}</p>
</md-list-item>
</md-list>
`;
return builder.overrideTemplate(TestList, template)
.createAsync(TestList).then((fixture) => {
fixture.detectChanges();
let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item'));
expect(listItems[0].nativeElement.className).toBe('md-2-line');
expect(listItems[1].nativeElement.className).toBe('md-2-line');
done();
});
});

it('should apply md-3-line class to lists with three lines', (done: () => void) => {
var template = `
<md-list>
<md-list-item *ngFor="#item of items">
<h3 md-line>{{item.name}}</h3>
<p md-line>{{item.description}}</p>
<p md-line>Some other text</p>
</md-list-item>
</md-list>
`;
return builder.overrideTemplate(TestList, template)
.createAsync(TestList).then((fixture) => {
fixture.detectChanges();
let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item'));
expect(listItems[0].nativeElement.className).toBe('md-3-line');
expect(listItems[1].nativeElement.className).toBe('md-3-line');
done();
});
});

it('should apply md-list-avatar class to list items with avatars', (done: () => void) => {
var template = `
<md-list>
<md-list-item>
<img src="" md-list-avatar>
Paprika
</md-list-item>
<md-list-item>
Pepper
</md-list-item>
</md-list>
`;
return builder.overrideTemplate(TestList, template)
.createAsync(TestList).then((fixture) => {
fixture.detectChanges();
let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item'));
expect(listItems[0].nativeElement.className).toBe('md-list-avatar');
expect(listItems[1].nativeElement.className).toBe('');
done();
});
});

it('should not clear custom classes provided by user', (done: () => void) => {
var template = `
<md-list>
<md-list-item class="test-class" *ngFor="#item of items">
<h3 md-line>{{item.name}}</h3>
<p md-line>{{item.description}}</p>
</md-list-item>
</md-list>
`;
return builder.overrideTemplate(TestList, template)
.createAsync(TestList).then((fixture) => {
fixture.detectChanges();
let listItems = fixture.debugElement.children[0].queryAll(By.css('md-list-item'));
expect(listItems[0].nativeElement.classList.contains('test-class')).toBe(true);
done();
});
});

it('should update classes if number of lines change', (done: () => void) => {
var template = `
<md-list>
<md-list-item *ngFor="#item of items">
<h3 md-line>{{item.name}}</h3>
<p md-line>{{item.description}}</p>
<p md-line *ngIf="showThirdLine">Some other text</p>
</md-list-item>
</md-list>
`;
return builder.overrideTemplate(TestList, template)
.createAsync(TestList).then((fixture) => {
fixture.debugElement.componentInstance.showThirdLine = false;
fixture.detectChanges();
let listItem = fixture.debugElement.children[0].query(By.css('md-list-item'));
expect(listItem.nativeElement.className).toBe('md-2-line');

fixture.debugElement.componentInstance.showThirdLine = true;
fixture.detectChanges();
setTimeout(() => {
expect(listItem.nativeElement.className).toBe('md-3-line');
done();
});
});
});

it('should add aria roles properly', (done: () => void) => {
var template = `
<md-list>
<md-list-item *ngFor="#item of items">
{{item.name}}
</md-list-item>
</md-list>
`;
return builder.overrideTemplate(TestList, template)
.createAsync(TestList).then((fixture) => {
fixture.detectChanges();
let list = fixture.debugElement.children[0];
let listItem = fixture.debugElement.children[0].query(By.css('md-list-item'));
expect(list.nativeElement.getAttribute('role')).toBe('list');
expect(listItem.nativeElement.getAttribute('role')).toBe('listitem');
done();
});
});

});
}

@Component({
selector: 'test-list',
template: ``,
directives: [MD_LIST_DIRECTIVES]
})
class TestList {
items: any[] = [
{'name': 'Paprika', 'description': 'A seasoning'},
{'name': 'Pepper', 'description': 'Another seasoning'}
];
showThirdLine: boolean = false;
}
Loading

0 comments on commit fb71eb1

Please sign in to comment.