Skip to content

Commit c45aaa6

Browse files
committed
feat(table): Add skeleton state
1 parent aea73dc commit c45aaa6

File tree

2 files changed

+83
-10
lines changed

2 files changed

+83
-10
lines changed

src/table/table.component.ts

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import {
88
import { Subscription, fromEvent } from "rxjs";
99

1010
import { TableModel } from "./table.module";
11+
import { TableHeaderItem } from "./table-header-item.class";
12+
import { TableItem } from "./table-item.class";
1113
import { getScrollbarWidth } from "../common/utils";
1214
import { I18n } from "./../i18n/i18n.module";
1315

@@ -165,12 +167,13 @@ import { I18n } from "./../i18n/i18n.module";
165167
[ngClass]="{
166168
'bx--data-table-v2--compact': size === 'sm',
167169
'bx--data-table-v2--tall': size === 'lg',
168-
'bx--data-table-v2--zebra': striped
170+
'bx--data-table-v2--zebra': striped,
171+
'bx--skeleton': skeleton
169172
}">
170173
<thead>
171174
<tr>
172175
<th *ngIf="model.hasExpandableRows()"></th>
173-
<th *ngIf="showSelectionColumn" style="width: 10px;">
176+
<th *ngIf="!skeleton && showSelectionColumn" style="width: 10px;">
174177
<ibm-checkbox
175178
[size]="size !== ('lg' ? 'sm' : 'md')"
176179
[(ngModel)]="selectAllCheckbox"
@@ -215,7 +218,7 @@ import { I18n } from "./../i18n/i18n.module";
215218
</button>
216219
<span
217220
class="bx--table-header-label"
218-
*ngIf="this.sort.observers.length === 0 || (this.sort.observers.length > 0 && !column.sortable)">
221+
*ngIf="!skeleton && this.sort.observers.length === 0 || (this.sort.observers.length > 0 && !column.sortable)">
219222
<span *ngIf="!column.template" [title]="column.data">{{column.data}}</span>
220223
<ng-template
221224
[ngTemplateOutlet]="column.template" [ngTemplateOutletContext]="{data: column.data}">
@@ -271,7 +274,7 @@ import { I18n } from "./../i18n/i18n.module";
271274
</div>
272275
</th>
273276
</ng-container>
274-
<th [ngStyle]="{'width': scrollbarWidth + 'px', 'padding': 0, 'border': 0}">
277+
<th *ngIf="!skeleton" [ngStyle]="{'width': scrollbarWidth + 'px', 'padding': 0, 'border': 0}">
275278
<!--
276279
Scrollbar pushes body to the left so this header column is added to push
277280
the title bar the same amount and keep the header and body columns aligned.
@@ -311,19 +314,20 @@ import { I18n } from "./../i18n/i18n.module";
311314
</svg>
312315
</button>
313316
</td>
314-
<td *ngIf="showSelectionColumn">
317+
<td *ngIf="!skeleton && showSelectionColumn">
315318
<ibm-checkbox
316319
aria-label="Select row"
317320
[size]="size !== ('lg' ? 'sm' : 'md')"
318321
[(ngModel)]="model.rowsSelected[i]"
319322
(change)="onRowCheckboxChange(i)">
320323
</ibm-checkbox>
321324
</td>
322-
<ng-container *ngFor="let item of row; let i = index">
323-
<td *ngIf="model.header[i].visible"
324-
[class]="model.header[i].className"
325-
[ngStyle]="model.header[i].style">
325+
<ng-container *ngFor="let item of row; let j = index">
326+
<td *ngIf="model.header[j].visible"
327+
[class]="model.header[j].className"
328+
[ngStyle]="model.header[j].style">
326329
<ng-container *ngIf="!item.template">{{item.data}}</ng-container>
330+
<span *ngIf="skeleton && i === 0"></span>
327331
<ng-template
328332
[ngTemplateOutlet]="item.template" [ngTemplateOutletContext]="{data: item.data}">
329333
</ng-template>
@@ -364,13 +368,42 @@ import { I18n } from "./../i18n/i18n.module";
364368
`
365369
})
366370
export class Table {
371+
/**
372+
* Creates a skeleton model with a row and column count specified by the user
373+
*
374+
* @param {number} rowCount
375+
* @param {number} columnCount
376+
*/
377+
static skeletonModelHeader(rowCount: number, columnCount: number) {
378+
const model = new TableModel();
379+
let header = new Array<TableHeaderItem>();
380+
let data = new Array<Array<TableItem>>();
381+
let row = new Array<TableItem>();
382+
383+
for (let i = 0; i < columnCount; i++) {
384+
header.push(new TableHeaderItem());
385+
row.push(new TableItem());
386+
}
387+
for (let j = 0; j < rowCount - 1 ; j++) {
388+
data.push(row);
389+
}
390+
391+
model.header = header;
392+
model.data = data;
393+
return model;
394+
}
395+
367396
/**
368397
* Size of the table rows.
369398
*
370399
* @type {("sm" | "md" | "lg")}
371400
* @memberof Table
372401
*/
373402
@Input() size: "sm" | "md" | "lg" = "md";
403+
/**
404+
* Set to `true` for a loading table.
405+
*/
406+
@Input() skeleton = false;
374407
/**
375408
* Object of all the strings table needs.
376409
* Defaults to the `TABLE` value from the i18n service.

src/table/table.stories.ts

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
} from "@storybook/addon-knobs/angular";
1818

1919
import {
20+
Table,
2021
TableModule,
2122
TableModel,
2223
TableItem,
@@ -414,6 +415,29 @@ function sort(model, index: number) {
414415
model.sort(index);
415416
}
416417

418+
@Component({
419+
selector: "app-skeleton-table",
420+
template: `
421+
<ibm-table
422+
[model]="skeletonModel"
423+
[skeleton]="skeleton"
424+
[size]="size"
425+
[striped]="striped">
426+
<ng-content></ng-content>
427+
</ibm-table>
428+
`
429+
})
430+
class SkeletonTableStory implements OnInit, OnChanges {
431+
@Input() size = "md";
432+
@Input() striped = false;
433+
@Input() skeleton = true;
434+
@Input() skeletonModel = new TableModel();
435+
436+
ngOnInit() {
437+
// Creates an empty table with 5 rows and 5 columns
438+
this.skeletonModel = Table.skeletonModelHeader(5, 5);
439+
}
440+
}
417441

418442
storiesOf("Table", module).addDecorator(
419443
moduleMetadata({
@@ -428,7 +452,8 @@ storiesOf("Table", module).addDecorator(
428452
DynamicTableStory,
429453
ExpansionTableStory,
430454
OverflowTableStory,
431-
PaginationTableStory
455+
PaginationTableStory,
456+
SkeletonTableStory
432457
]
433458
})
434459
)
@@ -525,5 +550,20 @@ storiesOf("Table", module).addDecorator(
525550
model: simpleModel,
526551
totalDataLength: number("totalDataLength", 105)
527552
}
553+
}))
554+
.add("Skeleton", () => ({
555+
template: `
556+
<div style="width: 800px">
557+
<app-skeleton-table
558+
[skeletonModel]="skeletonModel"
559+
[size]="size"
560+
[striped]="striped">
561+
</app-skeleton-table>
562+
</div>
563+
`,
564+
props: {
565+
size: selectV2("size", {Small: "sm", Normal: "md", Large: "lg"}, "md"),
566+
striped: boolean("striped", false)
567+
}
528568
}));
529569

0 commit comments

Comments
 (0)