diff --git a/docs/Admin.md b/docs/Admin.md
index 6a7bc3a513b..0151b08f3a8 100644
--- a/docs/Admin.md
+++ b/docs/Admin.md
@@ -162,36 +162,39 @@ If you want to add or remove menu items, for instance to link to non-resources p
// in src/Menu.js
import React, { createElement } from 'react';
import { connect } from 'react-redux';
+import { useMediaQuery } from '@material-ui/core';
import { MenuItemLink, getResources } from 'react-admin';
import { withRouter } from 'react-router-dom';
import LabelIcon from '@material-ui/icons/Label';
-import Responsive from '../layout/Responsive';
-
-const Menu = ({ resources, onMenuClick, logout }) => (
-
+ );
+}
const mapStateToProps = state => ({
+ open: state.admin.ui.sidebarOpen,
resources: getResources(state),
});
diff --git a/docs/Authentication.md b/docs/Authentication.md
index ef020f55318..e22ea196517 100644
--- a/docs/Authentication.md
+++ b/docs/Authentication.md
@@ -300,37 +300,25 @@ const MyLoginPage = ({ theme }) => {
export default MyLoginPage;
// in src/MyLogoutButton.js
-import React from 'react';
+import React, { forwardRef } from 'react';
import { useDispatch } from 'react-redux';
-import { Responsive, userLogout } from 'react-admin';
+import { userLogout } from 'react-admin';
import MenuItem from '@material-ui/core/MenuItem';
-import Button from '@material-ui/core/Button';
import ExitIcon from '@material-ui/icons/PowerSettingsNew';
-const MyLogoutButton = props => {
+const MyLogoutButton = forwardRef((props, ref) => {
const dispatch = useDispatch();
+ const logout = () => dispatch(userLogout(redirectTo));
return (
- dispatch(userLogout())}
- {...props}
- >
- Logout
-
- }
- medium={
-
- }
- />
+
);
-};
+});
+
export default MyLogoutButton;
// in src/App.js
diff --git a/docs/List.md b/docs/List.md
index a1d52b630a8..a8a34b1ecb5 100644
--- a/docs/List.md
+++ b/docs/List.md
@@ -1048,31 +1048,32 @@ export const PostList = (props) => (
`` iterates over the list data. For each record, it executes the `primaryText`, `secondaryText`, `leftAvatar`, `leftIcon`, `rightAvatar`, and `rightIcon` props function, and passes the result as the corresponding `` prop.
-**Tip**: To use a `` on small screens and a `` on larger screens, use the `` component:
+**Tip**: To use a `` on small screens and a `` on larger screens, use material-ui's `useMediaQuery` hook:
```jsx
// in src/posts.js
import React from 'react';
-import { List, Responsive, SimpleList, Datagrid, TextField, ReferenceField, EditButton } from 'react-admin';
+import { useMediaQuery } from '@material-ui/core';
+import { List, SimpleList, Datagrid, TextField, ReferenceField, EditButton } from 'react-admin';
-export const PostList = (props) => (
-
- {
+ const isSmall = useMediaQuery(theme => theme.breakpoints.down('sm'));
+ return (
+
+ {isSmall ? (
record.title}
secondaryText={record => `${record.views} views`}
tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
/>
- }
- medium={
+ ) : (
...
- }
- />
-
-);
+ )}
+
+ );
+}
```
**Tip**: The `` items link to the edition page by default. You can set the `linkType` prop to `show` to link to the `` page instead.
@@ -1281,21 +1282,21 @@ const UserFilter = ({ permissions, ...props }) =>
{permissions === 'admin' ? : null}
;
-export const UserList = ({ permissions, ...props }) =>
- }
- sort={{ field: 'name', order: 'ASC' }}
- >
- {
+ const isSmall = useMediaQuery(theme => theme.breakpoints.down('sm'));
+ return (
+ }
+ sort={{ field: 'name', order: 'ASC' }}
+ >
+ {isSmall ? (
record.name}
secondaryText={record =>
permissions === 'admin' ? record.role : null}
/>
- }
- medium={
+ ): (
@@ -1303,9 +1304,10 @@ export const UserList = ({ permissions, ...props }) =>
{permissions === 'admin' && }
- }
- />
- ;
+ )}
+ ;
+ )
+}
```
{% endraw %}
diff --git a/docs/Reference.md b/docs/Reference.md
index b718c69b1c7..83307aef8e5 100644
--- a/docs/Reference.md
+++ b/docs/Reference.md
@@ -68,7 +68,6 @@ title: "Reference"
* [``](./Fields.md#referencemanyfield)
* ``
* [``](./Resource.md#the-resource-component)
-* [``](./Theming.md#responsive-utility)
* [``](./Fields.md#richtextfield)
* [``](./Inputs.md#richtextinput)
* ``
diff --git a/docs/Theming.md b/docs/Theming.md
index 39bb2fbb9af..e953bf6d5dc 100644
--- a/docs/Theming.md
+++ b/docs/Theming.md
@@ -221,28 +221,43 @@ export const PostList = (props) => (
If you want to read more about higher-order components, check out this SitePoint tutorial: [Higher Order Components: A React Application Design Pattern](https://www.sitepoint.com/react-higher-order-components/)
-## Responsive Utility
+## useMediaQuery Hook
-To provide an optimized experience on mobile, tablet, and desktop devices, you often need to display different components depending on the screen size. That's the purpose of the `` component, which offers a declarative approach to responsive web design.
+To provide an optimized experience on mobile, tablet, and desktop devices, you often need to display different components depending on the screen size. Material-ui provides a hook dedicated to help such responsive layouts: [`useMediaQuery`](https://material-ui.com/components/use-media-query/#usemediaquery).
-It expects element props named `small`, `medium`, and `large`. It displays the element that matches the screen size (with breakpoints at 768 and 992 pixels):
+It expects a function receiving the material-ui theme as a parameter, and returning a media query. Use the theme breakpoints to check for common screen sizes. The hook returns a boolean indicating if the current screen matches the media query or not.
+
+```jsx
+const isXSmall = useMediaQuery(theme => theme.breakpoints.down('xs'));
+const isSmall = useMediaQuery(theme => theme.breakpoints.down('sm'));
+const isDesktop = useMediaQuery(theme => theme.breakpoints.up('md'));
+```
+
+You can also pass a custom media query as a screen.
+
+```jsx
+const isSmall = useMediaQuery('(min-width:600px)');
+```
+
+Here is an example for a responsive list of posts, displaying a `SimpleList` on mobile, and a `Datagrid` otherwise:
```jsx
// in src/posts.js
import React from 'react';
-import { List, Responsive, SimpleList, Datagrid, TextField, ReferenceField, EditButton } from 'react-admin';
-
-export const PostList = (props) => (
-
- {
+ const isSmall = useMediaQuery(theme => theme.breakpoints.down('sm'));
+ return (
+
+ {isSmall ? (
record.title}
secondaryText={record => `${record.views} views`}
tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
/>
- }
- medium={
+ ) : (
@@ -252,17 +267,13 @@ export const PostList = (props) => (
- }
- />
-
-);
+ )}
+
+ );
+}
```
-**Tip**: If you only provide `small` and `medium`, the `medium` element will also be used on large screens. The same kind of smart default exists for when you omit `small` or `medium`.
-
-**Tip**: You can specify `null` as the value for `small`, `medium` or `large` to avoid rendering something on a specific size without falling back to others.
-
-**Tip**: You can also use [material-ui's `withWidth()` higher order component](https://github.com/callemall/material-ui/blob/master/src/utils/withWidth.js) to have the `with` prop injected in your own components.
+**Tip**: Previous versions of react-admin shipped a `` component to do media queries. This component us now deprecated. Use `useMediaQuery` instead.
## Using a Predefined Theme
@@ -659,37 +670,46 @@ By default, React-admin uses the list of `` components passed as child
If you want to add or remove menu items, for instance to link to non-resources pages, you can create your own menu component:
```jsx
-// in src/MyMenu.js
-import React from 'react';
+// in src/Menu.js
+import React, { createElement } from 'react';
import { connect } from 'react-redux';
-import { MenuItemLink, getResources, Responsive } from 'react-admin';
+import { useMediaQuery } from '@material-ui/core';
+import { MenuItemLink, getResources } from 'react-admin';
import { withRouter } from 'react-router-dom';
+import LabelIcon from '@material-ui/icons/Label';
-const MyMenu = ({ resources, onMenuClick, logout }) => (
-
+ );
+}
const mapStateToProps = state => ({
+ open: state.admin.ui.sidebarOpen,
resources: getResources(state),
});
-export default withRouter(connect(mapStateToProps)(MyMenu));
-
+export default withRouter(connect(mapStateToProps)(Menu));
```
**Tip**: Note the `MenuItemLink` component. It must be used to avoid unwanted side effects in mobile views.
@@ -742,44 +762,46 @@ The `MenuItemLink` component make use of the React Router [`NavLink`](https://re
If the default active style does not suit your tastes, you can override it by passing your own `classes`:
```jsx
-// in src/MyMenu.js
-import React from 'react';
+// in src/Menu.js
+import React, { createElement } from 'react';
import { connect } from 'react-redux';
-import { MenuItemLink, getResources, Responsive } from 'react-admin';
-import { withStyles } from '@material-ui/core/styles';
+import { useMediaQuery } from '@material-ui/core';
+import { MenuItemLink, getResources } from 'react-admin';
import { withRouter } from 'react-router-dom';
+import LabelIcon from '@material-ui/icons/Label';
-const styles = {
- root: {}, // Style applied to the MenuItem from material-ui
- active: { fontWeight: 'bold' }, // Style applied when the menu item is the active one
- icon: {}, // Style applied to the icon
-};
-
-const MyMenu = ({ classes, resources, onMenuClick, logout }) => (
-
+ );
+}
const mapStateToProps = state => ({
+ open: state.admin.ui.sidebarOpen,
resources: getResources(state),
});
-export default withRouter(connect(mapStateToProps)(withStyles(styles)(Menu)));
+export default withRouter(connect(mapStateToProps)(Menu));
```
## Using a Custom Login Page
diff --git a/docs/Tutorial.md b/docs/Tutorial.md
index 38bd35c9cfe..470d79d28e6 100644
--- a/docs/Tutorial.md
+++ b/docs/Tutorial.md
@@ -741,24 +741,25 @@ The `` component uses [material-ui's `` and `` compo
**Note:** Since JSONRestServer doesn't provide `views` or `published_at` values for posts, we switched to a custom API for those screenshots in order to demonstrate how to use some of the `SimpleList` component props.
-That works fine on mobile, but now the desktop user experience is worse. The best compromise would be to use `` on small screens, and `` on other screens. That's where the `` component comes in:
+That works fine on mobile, but now the desktop user experience is worse. The best compromise would be to use `` on small screens, and `` on other screens. That's where the `useMediaQuery` hook comes in:
```jsx
// in src/posts.js
import React from 'react';
-import { List, Responsive, SimpleList, Datagrid, TextField, ReferenceField, EditButton } from 'react-admin';
+import { useMediaQuery } from '@material-ui/core';
+import { List, SimpleList, Datagrid, TextField, ReferenceField, EditButton } from 'react-admin';
-export const PostList = (props) => (
-
- {
+ const isSmall = useMediaQuery(theme => theme.breakpoints.down('sm'));
+ return (
+
+ {isSmall ? (
record.title}
secondaryText={record => `${record.views} views`}
tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
/>
- }
- medium={
+ ) : (
@@ -768,13 +769,13 @@ export const PostList = (props) => (
- }
- />
-
-);
+ )}
+
+ );
+}
```
-This works exactly the way you expect. The lesson here is that react-admin takes care of responsive web design for the layout, but it's your job to use `` in pages.
+This works exactly the way you expect. The lesson here is that react-admin takes care of responsive web design for the layout, but it's your job to use `useMediaQuery()` in pages.
![Responsive List](./img/responsive-list.gif)
diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html
index c7d88f8f968..12bedbfcdb7 100644
--- a/docs/_layouts/default.html
+++ b/docs/_layouts/default.html
@@ -693,7 +693,7 @@
Conditional Formatting