Skip to content

Commit d87ae3c

Browse files
authored
feat(material-experimental/mdc-paginator): implement MDC-based paginator (#20607)
Implements `mat-paginator` on top of MDC Web and the logic from the existing paginator. The structural styles are close to what we have in the current paginator, while the theming and typography are implemented on top of MDC's mixins. Furthermore, we're using the MDC versions of `mat-select` and `mat-button` inside the paginator. There are the following gotchas in this implementation: 1. The `mat-form-field` inside the paginator is set to always use the densest layout possible. This is necessary, because the MDC form field is too tall by default. 2. We hide one internal element from the form field, because it throws off the vertical alignment and is only used for hints and error messages which the paginator doesn't have. 3. I had to duplicate the `MatPaginatorDefaultOptions` interface, because the appearance of the MDC form field doesn't support the `legacy` and `standard` values.
1 parent 4b37b98 commit d87ae3c

31 files changed

+1397
-53
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
/src/material-experimental/mdc-list/** @mmalerba @devversion
110110
/src/material-experimental/mdc-menu/** @crisbeto
111111
/src/material-experimental/mdc-select/** @crisbeto
112+
/src/material-experimental/mdc-paginator/** @crisbeto
112113
/src/material-experimental/mdc-progress-spinner/** @andrewseguin
113114
/src/material-experimental/mdc-progress-bar/** @andrewseguin
114115
/src/material-experimental/mdc-radio/** @mmalerba
@@ -183,6 +184,7 @@
183184
/src/dev-app/mdc-input/** @devversion @mmalerba
184185
/src/dev-app/mdc-list/** @mmalerba
185186
/src/dev-app/mdc-menu/** @crisbeto
187+
/src/dev-app/mdc-paginator/** @crisbeto
186188
/src/dev-app/mdc-progress-bar/** @crisbeto
187189
/src/dev-app/mdc-progress-spinner/** @annieyw @mmalerba
188190
/src/dev-app/mdc-radio/** @mmalerba

.ng-dev/commit-message.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export const commitMessage: CommitMessageConfig = {
5252
'material-experimental/mdc-input',
5353
'material-experimental/mdc-list',
5454
'material-experimental/mdc-menu',
55+
'material-experimental/mdc-paginator',
5556
'material-experimental/mdc-progress-bar',
5657
'material-experimental/mdc-progress-spinner',
5758
'material-experimental/mdc-radio',

src/dev-app/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ ng_module(
5656
"//src/dev-app/mdc-input",
5757
"//src/dev-app/mdc-list",
5858
"//src/dev-app/mdc-menu",
59+
"//src/dev-app/mdc-paginator",
5960
"//src/dev-app/mdc-progress-bar",
6061
"//src/dev-app/mdc-progress-spinner",
6162
"//src/dev-app/mdc-radio",

src/dev-app/dev-app/dev-app-layout.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ export class DevAppLayout {
9191
{name: 'MDC List', route: '/mdc-list'},
9292
{name: 'MDC Menu', route: '/mdc-menu'},
9393
{name: 'MDC Radio', route: '/mdc-radio'},
94+
{name: 'MDC Paginator', route: '/mdc-paginator'},
9495
{name: 'MDC Progress Bar', route: '/mdc-progress-bar'},
9596
{name: 'MDC Progress Spinner', route: '/mdc-progress-spinner'},
9697
{name: 'MDC Tabs', route: '/mdc-tabs'},

src/dev-app/dev-app/routes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ export const DEV_APP_ROUTES: Routes = [
8989
{path: 'mdc-input', loadChildren: 'mdc-input/mdc-input-demo-module#MdcInputDemoModule'},
9090
{path: 'mdc-list', loadChildren: 'mdc-list/mdc-list-demo-module#MdcListDemoModule'},
9191
{path: 'mdc-menu', loadChildren: 'mdc-menu/mdc-menu-demo-module#MdcMenuDemoModule'},
92+
{
93+
path: 'mdc-paginator',
94+
loadChildren: 'mdc-paginator/mdc-paginator-demo-module#MdcPaginatorDemoModule'
95+
},
9296
{
9397
path: 'mdc-progress-spinner',
9498
loadChildren:

src/dev-app/mdc-paginator/BUILD.bazel

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
load("//tools:defaults.bzl", "ng_module", "sass_binary")
2+
3+
package(default_visibility = ["//visibility:public"])
4+
5+
ng_module(
6+
name = "mdc-paginator",
7+
srcs = glob(["**/*.ts"]),
8+
assets = [
9+
"mdc-paginator-demo.html",
10+
":mdc_paginator_demo_scss",
11+
],
12+
deps = [
13+
"//src/material-experimental/mdc-card",
14+
"//src/material-experimental/mdc-form-field",
15+
"//src/material-experimental/mdc-input",
16+
"//src/material-experimental/mdc-paginator",
17+
"//src/material-experimental/mdc-slide-toggle",
18+
"@npm//@angular/forms",
19+
"@npm//@angular/router",
20+
],
21+
)
22+
23+
sass_binary(
24+
name = "mdc_paginator_demo_scss",
25+
src = "mdc-paginator-demo.scss",
26+
)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {CommonModule} from '@angular/common';
10+
import {NgModule} from '@angular/core';
11+
import {FormsModule} from '@angular/forms';
12+
import {MatCardModule} from '@angular/material-experimental/mdc-card';
13+
import {MatFormFieldModule} from '@angular/material-experimental/mdc-form-field';
14+
import {MatInputModule} from '@angular/material-experimental/mdc-input';
15+
import {MatPaginatorModule} from '@angular/material-experimental/mdc-paginator';
16+
import {MatSlideToggleModule} from '@angular/material-experimental/mdc-slide-toggle';
17+
import {RouterModule} from '@angular/router';
18+
import {MdcPaginatorDemo} from './mdc-paginator-demo';
19+
20+
@NgModule({
21+
imports: [
22+
CommonModule,
23+
FormsModule,
24+
MatCardModule,
25+
MatFormFieldModule,
26+
MatInputModule,
27+
MatPaginatorModule,
28+
MatSlideToggleModule,
29+
RouterModule.forChild([{path: '', component: MdcPaginatorDemo}]),
30+
],
31+
declarations: [MdcPaginatorDemo],
32+
})
33+
export class MdcPaginatorDemoModule {
34+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<mat-card class="demo-section">
2+
<h2>No inputs</h2>
3+
<mat-paginator></mat-paginator>
4+
</mat-card>
5+
6+
<mat-card class="demo-section">
7+
<div class="demo-options">
8+
<mat-form-field>
9+
<mat-label>Length</mat-label>
10+
<input matInput type="number" [(ngModel)]="length">
11+
</mat-form-field>
12+
13+
<mat-form-field>
14+
<mat-label>Page Size</mat-label>
15+
<input matInput type="number" [(ngModel)]="pageSize">
16+
</mat-form-field>
17+
18+
<mat-form-field>
19+
<mat-label>Page Index</mat-label>
20+
<input matInput type="number" [(ngModel)]="pageIndex">
21+
</mat-form-field>
22+
23+
<mat-slide-toggle [(ngModel)]="hidePageSize">Hide page size</mat-slide-toggle>
24+
<mat-slide-toggle [(ngModel)]="showPageSizeOptions">Show multiple page size options</mat-slide-toggle>
25+
<mat-slide-toggle [(ngModel)]="showFirstLastButtons">Show first/last buttons</mat-slide-toggle>
26+
<mat-slide-toggle [(ngModel)]="disabled">Disabled</mat-slide-toggle>
27+
</div>
28+
29+
<mat-paginator #paginator
30+
(page)="handlePageEvent($event)"
31+
[length]="length"
32+
[pageSize]="pageSize"
33+
[disabled]="disabled"
34+
[showFirstLastButtons]="showFirstLastButtons"
35+
[pageSizeOptions]="showPageSizeOptions ? pageSizeOptions : []"
36+
[hidePageSize]="hidePageSize"
37+
[pageIndex]="pageIndex">
38+
</mat-paginator>
39+
40+
<div> Output event: {{pageEvent | json}} </div>
41+
<div> getNumberOfPages: {{paginator.getNumberOfPages()}} </div>
42+
</mat-card>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.demo-section {
2+
max-width: 600px;
3+
margin-bottom: 24px;
4+
padding: 16px;
5+
background: #efefef !important;
6+
7+
& > * {
8+
margin: 0 0 32px;
9+
}
10+
}
11+
12+
.demo-options {
13+
display: flex;
14+
flex-direction: column;
15+
max-width: 300px;
16+
17+
.mat-mdc-slide-toggle {
18+
margin-bottom: 8px;
19+
}
20+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Component} from '@angular/core';
10+
import {PageEvent} from '@angular/material-experimental/mdc-paginator';
11+
12+
@Component({
13+
selector: 'mdc-paginator-demo',
14+
templateUrl: 'mdc-paginator-demo.html',
15+
styleUrls: ['mdc-paginator-demo.css'],
16+
})
17+
export class MdcPaginatorDemo {
18+
length = 50;
19+
pageSize = 10;
20+
pageIndex = 0;
21+
pageSizeOptions = [5, 10, 25];
22+
23+
hidePageSize = false;
24+
showPageSizeOptions = true;
25+
showFirstLastButtons = true;
26+
disabled = false;
27+
28+
pageEvent: PageEvent;
29+
30+
handlePageEvent(e: PageEvent) {
31+
this.pageEvent = e;
32+
this.length = e.length;
33+
this.pageSize = e.pageSize;
34+
this.pageIndex = e.pageIndex;
35+
}
36+
}

src/dev-app/paginator/paginator-demo.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
background: #efefef !important;
55

66
& > * {
7-
margin: 32px 0;
7+
margin: 0 0 32px;
88
}
99
}
1010

src/dev-app/paginator/paginator-demo.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,13 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {Component, ViewEncapsulation} from '@angular/core';
9+
import {Component} from '@angular/core';
1010
import {PageEvent} from '@angular/material/paginator';
1111

1212
@Component({
1313
selector: 'paginator-demo',
1414
templateUrl: 'paginator-demo.html',
1515
styleUrls: ['paginator-demo.css'],
16-
encapsulation: ViewEncapsulation.None,
1716
})
1817
export class PaginatorDemo {
1918
length = 50;

src/material-experimental/config.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ entryPoints = [
2121
"mdc-list",
2222
"mdc-menu",
2323
"mdc-menu/testing",
24+
"mdc-paginator",
2425
"mdc-progress-bar",
2526
"mdc-progress-bar/testing",
2627
"mdc-progress-spinner",
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
load(
2+
"//tools:defaults.bzl",
3+
"ng_module",
4+
"ng_test_library",
5+
"ng_web_test_suite",
6+
"sass_binary",
7+
"sass_library",
8+
)
9+
10+
package(default_visibility = ["//visibility:public"])
11+
12+
ng_module(
13+
name = "mdc-paginator",
14+
srcs = glob(
15+
["**/*.ts"],
16+
exclude = ["**/*.spec.ts"],
17+
),
18+
assets = [":paginator.css"] + glob(["**/*.html"]),
19+
module_name = "@angular/material-experimental/mdc-paginator",
20+
deps = [
21+
"//src/material-experimental/mdc-button",
22+
"//src/material-experimental/mdc-select",
23+
"//src/material/paginator",
24+
"//src/material/tooltip",
25+
"@npm//@angular/common",
26+
"@npm//@angular/core",
27+
"@npm//@angular/forms", # TODO(jelbourn): transitive dep via generated code
28+
"@npm//rxjs",
29+
],
30+
)
31+
32+
sass_library(
33+
name = "mdc_paginator_scss_lib",
34+
srcs = glob(["**/_*.scss"]),
35+
deps = [
36+
"//src/material/core:core_scss_lib",
37+
],
38+
)
39+
40+
sass_binary(
41+
name = "mdc_paginator_scss",
42+
src = "paginator.scss",
43+
include_paths = [
44+
"external/npm/node_modules",
45+
],
46+
deps = [
47+
"//src/material-experimental/mdc-form-field:mdc_form_field_scss_lib",
48+
],
49+
)
50+
51+
ng_test_library(
52+
name = "mdc_paginator_tests_lib",
53+
srcs = glob(
54+
["**/*.spec.ts"],
55+
exclude = ["**/*.e2e.spec.ts"],
56+
),
57+
deps = [
58+
":mdc-paginator",
59+
"//src/cdk/testing/private",
60+
"//src/material-experimental/mdc-select",
61+
"//src/material/core",
62+
"@npm//@angular/platform-browser",
63+
],
64+
)
65+
66+
ng_web_test_suite(
67+
name = "unit_tests",
68+
static_files = [
69+
"@npm//:node_modules/@material/textfield/dist/mdc.textfield.js",
70+
"@npm//:node_modules/@material/line-ripple/dist/mdc.lineRipple.js",
71+
"@npm//:node_modules/@material/notched-outline/dist/mdc.notchedOutline.js",
72+
"@npm//:node_modules/@material/ripple/dist/mdc.ripple.js",
73+
"@npm//:node_modules/@material/dom/dist/mdc.dom.js",
74+
],
75+
deps = [
76+
":mdc_paginator_tests_lib",
77+
"//src/material-experimental:mdc_require_config.js",
78+
],
79+
)

0 commit comments

Comments
 (0)