The Pagination component enables the user to select a specific page from a range of pages.
-## Pagination
+## Basic pagination
{{"demo": "pages/components/pagination/BasicPagination.js"}}
@@ -45,9 +45,18 @@ Pagination supports two approaches for Router integration, the `renderItem` prop
{{"demo": "pages/components/pagination/PaginationLink.js"}}
-And children:
+## `usePagination`
-{{"demo": "pages/components/pagination/PaginationLinkChildren.js"}}
+For advanced customization use cases, we expose a `usePagination()` hook.
+It accepts almost the same options as the Pagination component minus all the props
+related to the rendering of JSX.
+The Pagination component uses this hook internally.
+
+```jsx
+import { usePagination } from '@material-ui/lab/Pagination';
+```
+
+{{"demo": "pages/components/pagination/UsePagination.js"}}
## Accessibility
diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
index 7c556b77758217..580e13ecc83dae 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
@@ -207,13 +207,13 @@ export const styles = theme => ({
'&[data-focus="true"]': {
backgroundColor: theme.palette.action.hover,
},
- '&[aria-disabled="true"]': {
- opacity: 0.5,
- pointerEvents: 'none',
- },
'&:active': {
backgroundColor: theme.palette.action.selected,
},
+ '&[aria-disabled="true"]': {
+ opacity: theme.palette.action.disabledOpacity,
+ pointerEvents: 'none',
+ },
},
/* Styles applied to the group's label elements. */
groupLabel: {
diff --git a/packages/material-ui-lab/src/Pagination/Pagination.js b/packages/material-ui-lab/src/Pagination/Pagination.js
index 28a063f135cae6..0d975e04be8f0d 100644
--- a/packages/material-ui-lab/src/Pagination/Pagination.js
+++ b/packages/material-ui-lab/src/Pagination/Pagination.js
@@ -7,48 +7,75 @@ import PaginationItem from '../PaginationItem';
export const styles = {
/* Styles applied to the root element. */
- root: {
+ root: {},
+ /* Styles applied to the ul element. */
+ ul: {
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
+ padding: 0,
+ margin: 0,
listStyle: 'none',
- padding: 0, // Reset
- margin: 0, // Reset
},
};
+function defaultGetAriaLabel(type, page, selected) {
+ if (type === 'page') {
+ return `${selected ? '' : 'Go to '}page ${page}`;
+ }
+ return `Go to ${type} page`;
+}
+
const Pagination = React.forwardRef(function Pagination(props, ref) {
+ /* eslint-disable no-unused-vars */
const {
+ boundaryCount = 1,
children,
classes,
className,
color = 'standard',
- getItemAriaLabel: getAriaLabel,
- items,
+ count = 1,
+ defaultPage = 1,
+ disabled = false,
+ getItemAriaLabel: getAriaLabel = defaultGetAriaLabel,
+ hideNextButton = false,
+ hidePrevButton = false,
renderItem = item => handleClick(event, page)}
+ focusVisibleClassName={classes.focusVisible}
className={clsx(
classes.root,
+ classes.page,
classes[variant],
classes[shape],
{
@@ -284,34 +240,10 @@ const PaginationItem = React.forwardRef(function PaginationItem(props, ref) {
{...other}
>
{type === 'page' && page}
- {type === 'previous' && (
-
- )}
- {type === 'next' && (
-
- )}
- {type === 'first' && (
-
- )}
- {type === 'last' && (
-
- )}
+ {type === 'previous' &&
}
+ {type === 'next' &&
}
+ {type === 'first' &&
}
+ {type === 'last' &&
}
);
});
@@ -338,22 +270,6 @@ PaginationItem.propTypes = {
* If `true`, the item will be disabled.
*/
disabled: PropTypes.bool,
- /**
- * Accepts a function which returns a string value that provides a user-friendly name for the current page.
- *
- * @param {string} [type = page] The link or button type to format ('page' | 'first' | 'last' | 'next' | 'previous').
- * @param {number} page The page number to format.
- * @param {bool} selected If true, the current page is selected.
- * @returns {string}
- */
- getAriaLabel: PropTypes.func,
- /**
- * Callback fired when the page is changed.
- *
- * @param {object} event The event source of the callback.
- * @param {number} page The page selected.
- */
- onClick: PropTypes.func,
/**
* The current page number.
*/
@@ -370,7 +286,7 @@ PaginationItem.propTypes = {
* The size of the pagination item.
*/
size: PropTypes.oneOf(['small', 'medium', 'large']),
- /*
+ /**
* The type of pagination item.
*/
type: PropTypes.oneOf([
@@ -382,10 +298,10 @@ PaginationItem.propTypes = {
'start-ellipsis',
'end-ellipsis',
]),
- /*
+ /**
* The pagination item variant.
*/
variant: PropTypes.oneOf(['text', 'outlined']),
};
-export default withStyles(styles, { name: 'PaginationItem' })(PaginationItem);
+export default withStyles(styles, { name: 'MuiPaginationItem' })(PaginationItem);
diff --git a/packages/material-ui-lab/src/PaginationItem/PaginationItem.test.js b/packages/material-ui-lab/src/PaginationItem/PaginationItem.test.js
index 33b5f1cf810daa..77bab8f33c33d1 100644
--- a/packages/material-ui-lab/src/PaginationItem/PaginationItem.test.js
+++ b/packages/material-ui-lab/src/PaginationItem/PaginationItem.test.js
@@ -1,6 +1,5 @@
import React from 'react';
import { expect } from 'chai';
-import { spy } from 'sinon';
import { createMount, getClasses } from '@material-ui/core/test-utils';
import describeConformance from '@material-ui/core/test-utils/describeConformance';
import { createClientRender } from 'test/utils/createClientRender';
@@ -9,10 +8,10 @@ import PaginationItem from './PaginationItem';
describe('
', () => {
let classes;
let mount;
- const render = createClientRender({ strict: false });
+ const render = createClientRender();
before(() => {
- mount = createMount();
+ mount = createMount({ strict: true });
classes = getClasses(
);
});
@@ -74,25 +73,4 @@ describe('
', () => {
expect(root).not.to.have.class(classes.sizeSmall);
expect(root).to.have.class(classes.sizeLarge);
});
-
- describe('prop: onClick', () => {
- it('should be called when clicked', () => {
- const handleClick = spy();
- const { getByRole } = render(
);
-
- getByRole('button').click();
-
- expect(handleClick.callCount).to.equal(1);
- });
-
- it('should be called with the button value', () => {
- const handleClick = spy();
- const { getByRole } = render(
);
-
- getByRole('button').click();
-
- expect(handleClick.callCount).to.equal(1);
- expect(handleClick.args[0][1]).to.equal(1);
- });
- });
});
diff --git a/packages/material-ui-lab/src/index.d.ts b/packages/material-ui-lab/src/index.d.ts
index a85a26e2c624a3..d54e40c2970cc3 100644
--- a/packages/material-ui-lab/src/index.d.ts
+++ b/packages/material-ui-lab/src/index.d.ts
@@ -10,6 +10,12 @@ export * from './Autocomplete';
export { default as AvatarGroup } from './AvatarGroup';
export * from './AvatarGroup';
+export { default as Pagination } from './Pagination';
+export * from './Pagination';
+
+export { default as PaginationItem } from './PaginationItem';
+export * from './PaginationItem';
+
export { default as Rating } from './Rating';
export * from './Rating';
diff --git a/packages/material-ui-lab/src/index.js b/packages/material-ui-lab/src/index.js
index 61f7cdeff5d27d..6dad7c07deb324 100644
--- a/packages/material-ui-lab/src/index.js
+++ b/packages/material-ui-lab/src/index.js
@@ -14,6 +14,9 @@ export * from './AvatarGroup';
export { default as Pagination } from './Pagination';
export * from './Pagination';
+export { default as PaginationItem } from './PaginationItem';
+export * from './PaginationItem';
+
export { default as Rating } from './Rating';
export * from './Rating';
diff --git a/packages/material-ui-lab/src/internal/svg-icons/FirstPage.js b/packages/material-ui-lab/src/internal/svg-icons/FirstPage.js
index 153f53cf2eb0ce..55a9b3052438da 100644
--- a/packages/material-ui-lab/src/internal/svg-icons/FirstPage.js
+++ b/packages/material-ui-lab/src/internal/svg-icons/FirstPage.js
@@ -5,9 +5,6 @@ import createSvgIcon from './createSvgIcon';
* @ignore - internal component.
*/
export default createSvgIcon(
-
-
-
- ,
+
,
'FirstPage',
);
diff --git a/packages/material-ui/src/Breadcrumbs/Breadcrumbs.js b/packages/material-ui/src/Breadcrumbs/Breadcrumbs.js
index b546e487ae3cf6..5e8075f5611bc1 100644
--- a/packages/material-ui/src/Breadcrumbs/Breadcrumbs.js
+++ b/packages/material-ui/src/Breadcrumbs/Breadcrumbs.js
@@ -14,8 +14,8 @@ export const styles = {
display: 'flex',
flexWrap: 'wrap',
alignItems: 'center',
- padding: 0, // Reset
- margin: 0, // Reset
+ padding: 0,
+ margin: 0,
listStyle: 'none',
},
/* Styles applied to the li element. */
diff --git a/packages/material-ui/src/Button/Button.js b/packages/material-ui/src/Button/Button.js
index c4be83a1210232..0bee9981d51483 100644
--- a/packages/material-ui/src/Button/Button.js
+++ b/packages/material-ui/src/Button/Button.js
@@ -73,7 +73,7 @@ export const styles = theme => ({
theme.palette.type === 'light' ? 'rgba(0, 0, 0, 0.23)' : 'rgba(255, 255, 255, 0.23)'
}`,
'&$disabled': {
- border: `1px solid ${theme.palette.action.disabled}`,
+ border: `1px solid ${theme.palette.action.disabledBackground}`,
},
},
/* Styles applied to the root element if `variant="outlined"` and `color="primary"`. */
diff --git a/packages/material-ui/src/Fab/Fab.js b/packages/material-ui/src/Fab/Fab.js
index 99238c618e9184..51ba635aa68545 100644
--- a/packages/material-ui/src/Fab/Fab.js
+++ b/packages/material-ui/src/Fab/Fab.js
@@ -25,9 +25,6 @@ export const styles = theme => ({
},
color: theme.palette.getContrastText(theme.palette.grey[300]),
backgroundColor: theme.palette.grey[300],
- '&$focusVisible': {
- boxShadow: theme.shadows[6],
- },
'&:hover': {
backgroundColor: theme.palette.grey.A100,
// Reset on touch devices, it doesn't add specificity
@@ -39,6 +36,9 @@ export const styles = theme => ({
},
textDecoration: 'none',
},
+ '&$focusVisible': {
+ boxShadow: theme.shadows[6],
+ },
'&$disabled': {
color: theme.palette.action.disabled,
boxShadow: theme.shadows[0],
diff --git a/packages/material-ui/src/SvgIcon/SvgIcon.js b/packages/material-ui/src/SvgIcon/SvgIcon.js
index c4a31a818b57d3..3ed8bc101ec347 100644
--- a/packages/material-ui/src/SvgIcon/SvgIcon.js
+++ b/packages/material-ui/src/SvgIcon/SvgIcon.js
@@ -79,7 +79,7 @@ const SvgIcon = React.forwardRef(function SvgIcon(props, ref) {
focusable="false"
viewBox={viewBox}
color={htmlColor}
- aria-hidden={titleAccess ? null : 'true'}
+ aria-hidden={titleAccess ? undefined : 'true'}
role={titleAccess ? 'img' : 'presentation'}
ref={ref}
{...other}
diff --git a/packages/material-ui/src/SvgIcon/SvgIcon.test.js b/packages/material-ui/src/SvgIcon/SvgIcon.test.js
index 9a73a5072ec684..867fa32f3759ec 100644
--- a/packages/material-ui/src/SvgIcon/SvgIcon.test.js
+++ b/packages/material-ui/src/SvgIcon/SvgIcon.test.js
@@ -59,7 +59,7 @@ describe('
', () => {
,
);
assert.strictEqual(wrapper.find('title').text(), 'Network');
- assert.strictEqual(wrapper.props()['aria-hidden'], null);
+ assert.strictEqual(wrapper.props()['aria-hidden'], undefined);
});
});
diff --git a/packages/material-ui/src/locale/index.js b/packages/material-ui/src/locale/index.js
index 7fae658de6d2af..e890e33938698a 100644
--- a/packages/material-ui/src/locale/index.js
+++ b/packages/material-ui/src/locale/index.js
@@ -265,6 +265,27 @@ export const frFR = {
MuiAlert: {
closeText: 'Fermer',
},
+ MuiPagination: {
+ 'aria-label': 'pagination navigation',
+ getItemAriaLabel: (type, page, selected) => {
+ if (type === 'page') {
+ return `${selected ? '' : 'Aller à la '}page ${page}`;
+ }
+ if (type === 'first') {
+ return 'Aller à la première page';
+ }
+ if (type === 'last') {
+ return 'Aller à la dernière page';
+ }
+ if (type === 'next') {
+ return 'Aller à la page suivante';
+ }
+ if (type === 'previous') {
+ return 'Aller à la page précédente';
+ }
+ return undefined;
+ },
+ },
},
};
diff --git a/packages/material-ui/src/styles/createPalette.js b/packages/material-ui/src/styles/createPalette.js
index cbb66038ff7192..b9cdc2d3670219 100644
--- a/packages/material-ui/src/styles/createPalette.js
+++ b/packages/material-ui/src/styles/createPalette.js
@@ -43,6 +43,10 @@ export const light = {
disabled: 'rgba(0, 0, 0, 0.26)',
// The background color of a disabled action.
disabledBackground: 'rgba(0, 0, 0, 0.12)',
+ disabledOpacity: 0.38,
+ focus: 'rgba(0, 0, 0, 0.12)',
+ focusOpacity: 0.12,
+ activatedOpaciy: 0.12,
},
};
@@ -67,6 +71,10 @@ export const dark = {
selectedOpacity: 0.16,
disabled: 'rgba(255, 255, 255, 0.3)',
disabledBackground: 'rgba(255, 255, 255, 0.12)',
+ disabledOpacity: 0.38,
+ focus: 'rgba(255, 255, 255, 0.12)',
+ focusOpacity: 0.12,
+ activatedOpaciy: 0.24,
},
};