Skip to content

Commit 43806f6

Browse files
committed
feat(grid-list): add header and footer support
1 parent 55cc197 commit 43806f6

File tree

12 files changed

+265
-94
lines changed

12 files changed

+265
-94
lines changed

src/components/grid-list/grid-list.scss

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
1-
// TODO(kara): Review this to see if MD spec updates are needed
1+
@import "list-shared";
2+
3+
/* height of tile header or footer if it has one line */
4+
$md-grid-list-one-line-height: 48px;
5+
/* height of tile header or footer if it has two lines */
6+
$md-grid-list-two-line-height: 68px;
7+
/* side padding for text in tile headers and footers */
8+
$md-grid-list-text-padding: 16px;
9+
10+
/* font styles for text in tile headers and footers */
11+
$md-grid-list-font-size: 16px;
12+
$md-grid-list-secondary-font: 12px;
213

314
md-grid-list {
415
display: block;
@@ -29,32 +40,30 @@ md-grid-tile {
2940
// Headers & footers
3041
md-grid-tile-header,
3142
md-grid-tile-footer {
43+
@include md-line-base($md-grid-list-secondary-font);
44+
@include md-normalize-text();
45+
3246
display: flex;
33-
flex-direction: row;
3447
align-items: center;
35-
height: 48px;
48+
height: $md-grid-list-one-line-height;
3649
color: #fff;
3750
background: rgba(0, 0, 0, 0.18);
3851
overflow: hidden;
52+
padding: 0 $md-grid-list-text-padding;
53+
font-size: $md-grid-list-font-size;
3954

4055
// Positioning
4156
position: absolute;
4257
left: 0;
4358
right: 0;
4459

45-
h3,
46-
h4 {
47-
font-weight: 400;
48-
margin: 0 0 0 16px;
49-
}
50-
51-
h3 {
52-
font-size: 14px;
60+
&.md-2-line {
61+
height: $md-grid-list-two-line-height;
5362
}
63+
}
5464

55-
h4 {
56-
font-size: 12px;
57-
}
65+
.md-grid-list-text {
66+
@include md-line-wrapper-base();
5867
}
5968

6069
md-grid-tile-header {
@@ -64,4 +73,17 @@ md-grid-tile {
6473
md-grid-tile-footer {
6574
bottom: 0;
6675
}
76+
77+
[md-grid-avatar] {
78+
padding-right: $md-grid-list-text-padding;
79+
80+
[dir='rtl'] & {
81+
padding-right: 0;
82+
padding-left: $md-grid-list-text-padding;
83+
}
84+
85+
&:empty {
86+
display:none;
87+
}
88+
}
6789
}

src/components/grid-list/grid-list.spec.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {Component} from '@angular/core';
1212
import {By} from '@angular/platform-browser';
1313

1414
import {MD_GRID_LIST_DIRECTIVES, MdGridList} from './grid-list';
15-
import {MdGridTile} from './grid-tile';
15+
import {MdGridTile, MdGridTileText} from './grid-tile';
1616

1717
describe('MdGridList', () => {
1818
let builder: TestComponentBuilder;
@@ -374,6 +374,48 @@ describe('MdGridList', () => {
374374
});
375375
});
376376
});
377+
378+
it('should add not add any classes to footers without lines', () => {
379+
var template = `
380+
<md-grid-list cols="1">
381+
<md-grid-tile>
382+
<md-grid-tile-footer>
383+
I'm a footer!
384+
</md-grid-tile-footer>
385+
</md-grid-tile>
386+
</md-grid-list>
387+
`;
388+
389+
return builder.overrideTemplate(TestGridList, template)
390+
.createAsync(TestGridList).then((fixture: ComponentFixture<TestGridList>) => {
391+
fixture.detectChanges();
392+
393+
let footer = fixture.debugElement.query(By.directive(MdGridTileText));
394+
expect(footer.nativeElement.classList.contains('md-2-line')).toBe(false);
395+
});
396+
});
397+
398+
it('should add class to footers with two lines', () => {
399+
var template = `
400+
<md-grid-list cols="1">
401+
<md-grid-tile>
402+
<md-grid-tile-footer>
403+
<h3 md-line>First line</h3>
404+
<span md-line>Second line</span>
405+
</md-grid-tile-footer>
406+
</md-grid-tile>
407+
</md-grid-list>
408+
`;
409+
410+
return builder.overrideTemplate(TestGridList, template)
411+
.createAsync(TestGridList).then((fixture: ComponentFixture<TestGridList>) => {
412+
fixture.detectChanges();
413+
414+
let footer = fixture.debugElement.query(By.directive(MdGridTileText));
415+
expect(footer.nativeElement.classList.contains('md-2-line')).toBe(true);
416+
});
417+
});
418+
377419
});
378420

379421
@Component({

src/components/grid-list/grid-list.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
ElementRef,
1111
Optional
1212
} from '@angular/core';
13-
import {MdGridTile} from './grid-tile';
13+
import {MdGridTile, MdGridTileText} from './grid-tile';
1414
import {TileCoordinator} from './tile-coordinator';
1515
import {
1616
TileStyler,
@@ -20,6 +20,7 @@ import {
2020
} from './tile-styler';
2121
import {MdGridListColsError} from './grid-list-errors';
2222
import {Dir} from '@angular2-material/core/rtl/dir';
23+
import {MdLine} from '@angular2-material/core/line/line';
2324

2425
// TODO(kara): Conditional (responsive) column count / row size.
2526
// TODO(kara): Re-layout on window resize / media change (debounced).
@@ -167,4 +168,4 @@ export function coerceToNumber(value: string | number): number {
167168
return typeof value === 'string' ? parseInt(value, 10) : value;
168169
}
169170

170-
export const MD_GRID_LIST_DIRECTIVES: any[] = [MdGridList, MdGridTile];
171+
export const MD_GRID_LIST_DIRECTIVES: any[] = [MdGridList, MdGridTile, MdLine, MdGridTileText];
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<ng-content select="[md-grid-avatar]"></ng-content>
2+
<div class="md-grid-list-text"><ng-content select="[md-line]"></ng-content></div>
3+
<ng-content></ng-content>

src/components/grid-list/grid-tile.ts

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import {
44
Renderer,
55
ElementRef,
66
Input,
7+
ContentChildren,
8+
QueryList,
9+
AfterContentInit
710
} from '@angular/core';
8-
9-
import {coerceToNumber} from './grid-list';
11+
import { coerceToNumber } from './grid-list';
12+
import { MdLine, MdLineSetter } from '@angular2-material/core/line/line';
1013

1114
@Component({
1215
moduleId: module.id,
@@ -19,11 +22,8 @@ import {coerceToNumber} from './grid-list';
1922
export class MdGridTile {
2023
_rowspan: number = 1;
2124
_colspan: number = 1;
22-
_element: HTMLElement;
2325

24-
constructor(private _renderer: Renderer, element: ElementRef) {
25-
this._element = element.nativeElement;
26-
}
26+
constructor(private _renderer: Renderer, private _element: ElementRef) {}
2727

2828
@Input()
2929
get rowspan() {
@@ -48,7 +48,28 @@ export class MdGridTile {
4848
* @internal
4949
*/
5050
setStyle(property: string, value: string): void {
51-
this._renderer.setElementStyle(this._element, property, value);
51+
this._renderer.setElementStyle(this._element.nativeElement, property, value);
5252
}
5353

5454
}
55+
56+
@Component({
57+
moduleId: module.id,
58+
selector: 'md-grid-tile-header, md-grid-tile-footer',
59+
templateUrl: 'grid-tile-text.html'
60+
})
61+
export class MdGridTileText implements AfterContentInit {
62+
/**
63+
* Helper that watches the number of lines in a text area and sets
64+
* a class on the host element that matches the line count.
65+
*/
66+
_lineSetter: MdLineSetter;
67+
@ContentChildren(MdLine) _lines: QueryList<MdLine>;
68+
69+
constructor(private _renderer: Renderer, private _element: ElementRef) {}
70+
71+
ngAfterContentInit() {
72+
this._lineSetter = new MdLineSetter(this._lines, this._renderer, this._element);
73+
}
74+
}
75+

src/components/list/list.scss

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
@import "variables";
22
@import "default-theme";
3+
@import "list-shared";
34

45
$md-list-side-padding: 16px;
56
$md-list-avatar-size: 40px;
@@ -56,27 +57,12 @@ based on whether the list is in dense mode.
5657
}
5758

5859
.md-list-text {
59-
display: flex;
60-
flex-direction: column;
61-
width: 100%;
60+
@include md-line-wrapper-base();
6261
padding: 0 $md-list-side-padding;
63-
box-sizing: border-box;
64-
overflow: hidden;
6562

6663
&:first-child {
6764
padding: 0;
6865
}
69-
70-
&:empty {
71-
display: none;
72-
}
73-
74-
& > * {
75-
margin: 0;
76-
padding: 0;
77-
font-weight: normal;
78-
font-size: inherit;
79-
}
8066
}
8167

8268
[md-list-avatar] {
@@ -93,26 +79,6 @@ based on whether the list is in dense mode.
9379
}
9480
}
9581

96-
/*
97-
This mixin provides all md-line styles, changing secondary font size
98-
based on whether the list is in dense mode.
99-
*/
100-
@mixin md-line-base($secondary-font-size) {
101-
102-
[md-line] {
103-
display: block;
104-
white-space: nowrap;
105-
overflow-x: hidden;
106-
text-overflow: ellipsis;
107-
box-sizing: border-box;
108-
109-
// all lines but the top line should have smaller text
110-
&:nth-child(n+2) {
111-
font-size: $secondary-font-size;
112-
}
113-
}
114-
}
115-
11682
/*
11783
This mixin provides all subheader styles, adjusting heights and padding
11884
based on whether the list is in dense mode.

src/components/list/list.ts

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import {
99
Renderer,
1010
AfterContentInit,
1111
} from '@angular/core';
12-
13-
12+
import { MdLine, MdLineSetter } from '../../core/line/line';
1413

1514
@Component({
1615
moduleId: module.id,
@@ -22,10 +21,6 @@ import {
2221
})
2322
export class MdList {}
2423

25-
/* Need directive for a ContentChildren query in list-item */
26-
@Directive({ selector: '[md-line]' })
27-
export class MdLine {}
28-
2924
/* Need directive for a ContentChild query in list-item */
3025
@Directive({ selector: '[md-list-avatar]' })
3126
export class MdListAvatar {}
@@ -42,27 +37,25 @@ export class MdListAvatar {}
4237
encapsulation: ViewEncapsulation.None
4338
})
4439
export class MdListItem implements AfterContentInit {
45-
@ContentChildren(MdLine) _lines: QueryList<MdLine>;
46-
4740
/** @internal */
4841
hasFocus: boolean = false;
4942

50-
/** TODO: internal */
51-
ngAfterContentInit() {
52-
this._setLineClass(this._lines.length);
43+
_lineSetter: MdLineSetter;
5344

54-
this._lines.changes.subscribe(() => {
55-
this._setLineClass(this._lines.length);
56-
});
57-
}
45+
@ContentChildren(MdLine) _lines: QueryList<MdLine>;
5846

5947
@ContentChild(MdListAvatar)
6048
private set _hasAvatar(avatar: MdListAvatar) {
61-
this._setClass('md-list-avatar', avatar != null);
49+
this._renderer.setElementClass(this._element.nativeElement, 'md-list-avatar', avatar != null);
6250
}
6351

6452
constructor(private _renderer: Renderer, private _element: ElementRef) {}
6553

54+
/** TODO: internal */
55+
ngAfterContentInit() {
56+
this._lineSetter = new MdLineSetter(this._lines, this._renderer, this._element);
57+
}
58+
6659
/** @internal */
6760
handleFocus() {
6861
this.hasFocus = true;
@@ -72,22 +65,6 @@ export class MdListItem implements AfterContentInit {
7265
handleBlur() {
7366
this.hasFocus = false;
7467
}
75-
76-
private _setLineClass(count: number): void {
77-
this._resetClasses();
78-
if (count === 2 || count === 3) {
79-
this._setClass(`md-${count}-line`, true);
80-
}
81-
}
82-
83-
private _resetClasses(): void {
84-
this._setClass('md-2-line', false);
85-
this._setClass('md-3-line', false);
86-
}
87-
88-
private _setClass(className: string, bool: boolean): void {
89-
this._renderer.setElementClass(this._element.nativeElement, className, bool);
90-
}
9168
}
9269

9370
export const MD_LIST_DIRECTIVES = [MdList, MdListItem, MdLine, MdListAvatar];

0 commit comments

Comments
 (0)