Skip to content

Commit 8dc35d8

Browse files
Domino987Domino987
and
Domino987
authored
feat: improve showFirstLastPageButtons (#634)
Co-authored-by: Domino987 <domino987@gmail.com>
1 parent 7834cc4 commit 8dc35d8

File tree

7 files changed

+180
-13
lines changed

7 files changed

+180
-13
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import * as React from 'react';
2+
import {
3+
screen,
4+
render,
5+
waitForElementToBeRemoved
6+
} from '@testing-library/react';
7+
import MaterialTable from '../src';
8+
import '@testing-library/jest-dom';
9+
10+
describe('Show Pagination Buttons', () => {
11+
test('Show no buttons', async () => {
12+
render(
13+
<MaterialTable
14+
data={[
15+
{ name: 'Smith', notes: 'A common name' },
16+
{ name: 'Smith', notes: 'A common name' },
17+
{ name: 'Smith', notes: 'A common name' },
18+
{ name: 'Smith', notes: 'A common name' },
19+
{ name: 'Smith', notes: 'A common name' },
20+
{ name: 'Smith', notes: 'A common name' },
21+
{ name: 'Smith', notes: 'A common name' },
22+
{ name: 'Smith', notes: 'A common name' },
23+
{ name: 'Smith', notes: 'A common name' },
24+
{ name: 'Smith', notes: 'A common name' },
25+
{ name: 'Smith', notes: 'A common name' }
26+
]}
27+
columns={[
28+
{ title: 'Name', field: 'name', width: 40 },
29+
{ title: 'Notes', field: 'notes', width: 200 }
30+
]}
31+
options={{
32+
showFirstLastPageButtons: false
33+
}}
34+
/>
35+
);
36+
screen.getByRole('button', { name: /previous page/i });
37+
screen.getByRole('button', { name: /next page/i });
38+
expect(screen.queryByRole('button', { name: /first page/i })).toBeNull();
39+
expect(screen.queryByRole('button', { name: /last page/i })).toBeNull();
40+
});
41+
test('Show first buttons', async () => {
42+
render(
43+
<MaterialTable
44+
data={[
45+
{ name: 'Smith', notes: 'A common name' },
46+
{ name: 'Smith', notes: 'A common name' },
47+
{ name: 'Smith', notes: 'A common name' },
48+
{ name: 'Smith', notes: 'A common name' },
49+
{ name: 'Smith', notes: 'A common name' },
50+
{ name: 'Smith', notes: 'A common name' },
51+
{ name: 'Smith', notes: 'A common name' },
52+
{ name: 'Smith', notes: 'A common name' },
53+
{ name: 'Smith', notes: 'A common name' },
54+
{ name: 'Smith', notes: 'A common name' },
55+
{ name: 'Smith', notes: 'A common name' }
56+
]}
57+
columns={[
58+
{ title: 'Name', field: 'name', width: 40 },
59+
{ title: 'Notes', field: 'notes', width: 200 }
60+
]}
61+
options={{
62+
showFirstLastPageButtons: { last: false }
63+
}}
64+
/>
65+
);
66+
screen.getByRole('button', { name: /previous page/i });
67+
screen.getByRole('button', { name: /next page/i });
68+
screen.getByRole('button', { name: /first page/i });
69+
expect(screen.queryByRole('button', { name: /last page/i })).toBeNull();
70+
});
71+
test('Show last buttons', async () => {
72+
render(
73+
<MaterialTable
74+
data={[
75+
{ name: 'Smith', notes: 'A common name' },
76+
{ name: 'Smith', notes: 'A common name' },
77+
{ name: 'Smith', notes: 'A common name' },
78+
{ name: 'Smith', notes: 'A common name' },
79+
{ name: 'Smith', notes: 'A common name' },
80+
{ name: 'Smith', notes: 'A common name' },
81+
{ name: 'Smith', notes: 'A common name' },
82+
{ name: 'Smith', notes: 'A common name' },
83+
{ name: 'Smith', notes: 'A common name' },
84+
{ name: 'Smith', notes: 'A common name' },
85+
{ name: 'Smith', notes: 'A common name' }
86+
]}
87+
columns={[
88+
{ title: 'Name', field: 'name', width: 40 },
89+
{ title: 'Notes', field: 'notes', width: 200 }
90+
]}
91+
options={{
92+
showFirstLastPageButtons: { first: false }
93+
}}
94+
/>
95+
);
96+
screen.getByRole('button', { name: /previous page/i });
97+
screen.getByRole('button', { name: /next page/i });
98+
screen.getByRole('button', { name: /last page/i });
99+
expect(screen.queryByRole('button', { name: /first page/i })).toBeNull();
100+
});
101+
test('Show all buttons', async () => {
102+
render(
103+
<MaterialTable
104+
data={[
105+
{ name: 'Smith', notes: 'A common name' },
106+
{ name: 'Smith', notes: 'A common name' },
107+
{ name: 'Smith', notes: 'A common name' },
108+
{ name: 'Smith', notes: 'A common name' },
109+
{ name: 'Smith', notes: 'A common name' },
110+
{ name: 'Smith', notes: 'A common name' },
111+
{ name: 'Smith', notes: 'A common name' },
112+
{ name: 'Smith', notes: 'A common name' },
113+
{ name: 'Smith', notes: 'A common name' },
114+
{ name: 'Smith', notes: 'A common name' },
115+
{ name: 'Smith', notes: 'A common name' }
116+
]}
117+
columns={[
118+
{ title: 'Name', field: 'name', width: 40 },
119+
{ title: 'Notes', field: 'notes', width: 200 }
120+
]}
121+
options={{}}
122+
/>
123+
);
124+
125+
screen.getByRole('button', { name: /previous page/i });
126+
screen.getByRole('button', { name: /next page/i });
127+
screen.getByRole('button', { name: /first page/i });
128+
screen.getByRole('button', { name: /last page/i });
129+
});
130+
});

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
},
5555
"homepage": "https://material-table-core.com",
5656
"devDependencies": {
57-
"react": ">=16.8.0",
58-
"react-dom": ">=16.8.0",
57+
"react": ">=18.2.0",
58+
"react-dom": ">=18.2.0",
5959
"@babel/cli": "^7.12.10",
6060
"@babel/core": "^7.12.10",
6161
"@babel/plugin-proposal-class-properties": "^7.12.1",
@@ -65,8 +65,8 @@
6565
"@babel/preset-react": "^7.12.10",
6666
"@mui/styles": ">=5.0.0",
6767
"@material-table/exporters": "^1.0.12",
68-
"@testing-library/jest-dom": "^5.14.1",
69-
"@testing-library/react": "^12.0.0",
68+
"@testing-library/jest-dom": "^5.16.5",
69+
"@testing-library/react": "^13.4.0",
7070
"@types/jest": "^26.0.20",
7171
"@webpack-cli/serve": "^1.2.1",
7272
"@wojtekmaj/enzyme-adapter-react-17": "^0.4.1",

src/components/MTablePagination/index.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import PropTypes from 'prop-types';
66
import React from 'react';
77
import { Box } from '@mui/material';
88
import { useTheme } from '@mui/material/styles';
9+
import * as CommonValues from '../../utils/common-values';
910
import { useLocalizationStore, useIconStore } from '@store/LocalizationStore';
1011
/* eslint-enable no-unused-vars */
1112

@@ -40,6 +41,11 @@ function MTablePagination(props) {
4041
};
4142

4243
const { count, page, rowsPerPage, showFirstLastPageButtons } = props;
44+
45+
const { first, last } = CommonValues.parseFirstLastPageButtons(
46+
showFirstLastPageButtons,
47+
theme.direction === 'rtl'
48+
);
4349
return (
4450
<Box
4551
sx={{
@@ -50,7 +56,7 @@ function MTablePagination(props) {
5056
}}
5157
ref={props.forwardedRef}
5258
>
53-
{showFirstLastPageButtons && (
59+
{first && (
5460
<Tooltip title={localization.firstTooltip}>
5561
<span>
5662
<IconButton
@@ -118,7 +124,7 @@ function MTablePagination(props) {
118124
</IconButton>
119125
</span>
120126
</Tooltip>
121-
{showFirstLastPageButtons && (
127+
{last && (
122128
<Tooltip title={localization.lastTooltip}>
123129
<span>
124130
<IconButton
@@ -147,7 +153,10 @@ MTablePagination.propTypes = {
147153
rowsPerPage: PropTypes.number,
148154
classes: PropTypes.object,
149155
localization: PropTypes.object,
150-
showFirstLastPageButtons: PropTypes.bool,
156+
showFirstLastPageButtons: PropTypes.oneOfType([
157+
PropTypes.object,
158+
PropTypes.bool
159+
]),
151160
forwardedRef: PropTypes.func
152161
};
153162

src/components/MTableSteppedPaginationInner/index.js

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Button from '@mui/material/Button';
55
import PropTypes from 'prop-types';
66
import React from 'react';
77
import { useTheme } from '@mui/material/styles';
8+
import * as CommonValues from '../../utils/common-values';
89
import { useLocalizationStore, useIconStore } from '@store';
910

1011
function MTablePaginationInner(props) {
@@ -81,7 +82,10 @@ function MTablePaginationInner(props) {
8182

8283
const pageStart = Math.max(page - 1, 0);
8384
const pageEnd = Math.min(maxPages, page + 1);
84-
85+
const { first, last } = CommonValues.parseFirstLastPageButtons(
86+
showFirstLastPageButtons,
87+
theme.direction === 'rtl'
88+
);
8589
return (
8690
<Box
8791
sx={{
@@ -93,7 +97,7 @@ function MTablePaginationInner(props) {
9397
}}
9498
ref={props.forwardedRef}
9599
>
96-
{showFirstLastPageButtons && (
100+
{first && (
97101
<Tooltip title={localization.firstTooltip}>
98102
<span>
99103
<IconButton
@@ -141,7 +145,7 @@ function MTablePaginationInner(props) {
141145
</IconButton>
142146
</span>
143147
</Tooltip>
144-
{showFirstLastPageButtons && (
148+
{last && (
145149
<Tooltip title={localization.lastTooltip}>
146150
<span>
147151
<IconButton
@@ -172,7 +176,10 @@ MTablePaginationInner.propTypes = {
172176
numberOfPagesAround: PropTypes.number,
173177
classes: PropTypes.object,
174178
theme: PropTypes.any,
175-
showFirstLastPageButtons: PropTypes.bool
179+
showFirstLastPageButtons: PropTypes.oneOfType([
180+
PropTypes.object,
181+
PropTypes.bool
182+
])
176183
};
177184

178185
MTablePaginationInner.defaultProps = {

src/prop-types.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,10 @@ export const propTypes = {
368368
selection: PropTypes.bool,
369369
selectionProps: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
370370
showEmptyDataSourceMessage: PropTypes.bool,
371-
showFirstLastPageButtons: PropTypes.bool,
371+
showFirstLastPageButtons: PropTypes.oneOfType([
372+
PropTypes.object,
373+
PropTypes.bool
374+
]),
372375
showSelectAllCheckbox: PropTypes.bool,
373376
showSelectGroupCheckbox: PropTypes.bool,
374377
showTitle: PropTypes.bool,

src/utils/common-values.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,19 @@ export const widthToNumber = (width) => {
2828
if (!width || !width.match(/^\s*\d+(px)?\s*$/)) return NaN;
2929
return Number(width.replace(/px$/, ''));
3030
};
31+
32+
export const parseFirstLastPageButtons = (showFirstLastPageButtons, isRTL) => {
33+
let result = { first: true, last: true };
34+
if (typeof showFirstLastPageButtons === 'boolean') {
35+
result = {
36+
first: showFirstLastPageButtons,
37+
last: showFirstLastPageButtons
38+
};
39+
} else if (typeof showFirstLastPageButtons === 'object') {
40+
result = { ...result, ...showFirstLastPageButtons };
41+
}
42+
if (isRTL) {
43+
result = { first: result.last, last: result.first };
44+
}
45+
return result;
46+
};

types/index.d.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,9 @@ export interface Options<RowData extends object> {
415415
| React.CSSProperties
416416
| ((data: RowData, index: number, level: number) => React.CSSProperties);
417417
showEmptyDataSourceMessage?: boolean;
418-
showFirstLastPageButtons?: boolean;
418+
showFirstLastPageButtons?:
419+
| boolean
420+
| Partial<{ first: boolean; last: boolean }>;
419421
showSelectAllCheckbox?: boolean;
420422
showSelectGroupCheckbox?: boolean;
421423
showTitle?: boolean;

0 commit comments

Comments
 (0)