Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: Added at Rob's request to help travis pass.



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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comments for the two-line / three-line concept, as it may not be clear to someone unfamiliar with the spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean something like // lists with two and three lines require different heights in the spec?

$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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be good for these mixins to describe what's captured in the base and what is left to the specific uses.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

$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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add comment for this rule

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
}
}

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