Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix AppBar with alwaysOn hides sidebar menu on scroll #8856

Merged
merged 3 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions docs/AppBar.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ const App = () => (

| Prop | Required | Type | Default | Description |
| ------------------- | -------- | -------------- | -------- | --------------------------------------------------- |
| `alwaysOn` | Optional | `boolean` | - | When true, the app bar is always visible |
| `children` | Optional | `ReactElement` | - | What to display in the central part of the app bar |
| `color` | Optional | `string` | - | The background color of the app bar |
| `sx` | Optional | `SxProps` | - | Style overrides, powered by MUI System |
Expand All @@ -73,17 +72,6 @@ const App = () => (

Additional props are passed to [the underlying MUI `<AppBar>` element](https://mui.com/material-ui/api/app-bar/).

## `alwaysOn`

By default, the app bar is hidden when the user scrolls down the page. This is useful to save space on small screens. But if you want to keep the app bar always visible, you can set the `alwaysOn` prop to `true`.

```jsx
// in src/MyAppBar.js
import { AppBar } from 'react-admin';

const MyAppBar = () => <AppBar alwaysOn />;
```

## `children`

The `<AppBar>` component accepts a `children` prop, which is displayed in the central part of the app bar. This is useful to add buttons to the app bar, for instance, a light/dark theme switcher.
Expand Down
28 changes: 21 additions & 7 deletions docs/Layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,15 @@ const App = () => (

## Props

| Prop | Required | Type | Default | Description |
| ----------- | -------- | ----------- | -------- | --------------------------------------------------------------------- |
| `appBar` | Optional | `Component` | - | A React component rendered at the top of the layout |
| `className` | Optional | `string` | - | Passed to the root `<div>` component |
| `error` | Optional | `Component` | - | A React component rendered in the content area in case of error |
| `menu` | Optional | `Component` | - | A React component rendered at the side of the screen |
| `sx` | Optional | `SxProps` | - | Style overrides, powered by MUI System |
| Prop | Required | Type | Default | Description |
| ---------------- | -------- | ----------- | -------- | ----------------------------------------------------------------------- |
| `appBar` | Optional | `Component` | - | A React component rendered at the top of the layout |
| `appBarAlwaysOn` | Optional | `boolean` | - | When true, the app bar is always visible |
| `className` | Optional | `string` | - | Passed to the root `<div>` component |
| `error` | Optional | `Component` | - | A React component rendered in the content area in case of error |
| `menu` | Optional | `Component` | - | A React component rendered at the side of the screen |
| `sidebar` | Optional | `Component` | - | A React component responsible for rendering the menu (e.g. in a drawer) |
| `sx` | Optional | `SxProps` | - | Style overrides, powered by MUI System |

React-admin injects more props at runtime based on the `<Admin>` props:

Expand Down Expand Up @@ -114,6 +116,18 @@ export const MyAppBar = () => (

Check out the [`<AppBar>` documentation](./AppBar.md) for more information, and for instructions on building your own AppBar.

## `appBarAlwaysOn`

By default, the app bar is hidden when the user scrolls down the page. This is useful to save space on small screens. But if you want to keep the app bar always visible, you can set the `appBarAlwaysOn` prop to `true`.

```jsx
// in src/MyLayout.js
import * as React from 'react';
import { Layout } from 'react-admin';

export const MyLayout = (props) => <Layout {...props} appBarAlwaysOn />;
```

## `className`

`className` is passed to the root `<div>` component. It lets you style the layout with CSS - but the `sx` prop is preferred.
Expand Down
6 changes: 0 additions & 6 deletions packages/ra-ui-materialui/src/layout/AppBar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,6 @@ export const Color = () => (
</Wrapper>
);

export const AlwaysOn = () => (
<Wrapper>
<AppBar alwaysOn />
</Wrapper>
);

Comment on lines -77 to -82
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you should remove this story as this still works, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true but I don't want to encourage people to use it

export const Position = () => (
<Wrapper>
<AppBar position="sticky" />
Expand Down
5 changes: 5 additions & 0 deletions packages/ra-ui-materialui/src/layout/AppBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ AppBar.propTypes = {
const DefaultUserMenu = <UserMenu />;

export interface AppBarProps extends Omit<MuiAppBarProps, 'title'> {
/**
* This prop is injected by Layout. You should not use it directly unless
* you are using a custom layout.
* If you are using the default layout, use `<Layout appBarAlwaysOn>` instead.
*/
alwaysOn?: boolean;
container?: React.ElementType<any>;
/**
Expand Down
100 changes: 100 additions & 0 deletions packages/ra-ui-materialui/src/layout/Layout.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import {
Box,
ListItemIcon,
ListItemText,
MenuItem,
MenuList,
Skeleton,
ThemeProvider,
createTheme,
} from '@mui/material';
import DashboardIcon from '@mui/icons-material/Dashboard';
import ShoppingCartIcon from '@mui/icons-material/ShoppingCart';
import PeopleIcon from '@mui/icons-material/People';
import {
AuthContext,
PreferencesEditorContextProvider,
StoreContextProvider,
memoryStore,
} from 'ra-core';
import * as React from 'react';
import { QueryClient, QueryClientProvider } from 'react-query';
import { MemoryRouter } from 'react-router';

import { defaultTheme } from '../defaultTheme';
import { Layout } from './Layout';
import { Title } from './Title';

export default {
title: 'ra-ui-materialui/layout/Layout',
};

const Content = () => (
<Box>
<Skeleton
variant="text"
width="auto"
sx={{ fontSize: '2rem', mx: 2 }}
animation={false}
/>
<Skeleton
variant="rectangular"
width="auto"
height={1500}
sx={{ mx: 2 }}
animation={false}
/>
</Box>
);

const Wrapper = ({
children = <Content />,
theme = createTheme(defaultTheme),
layout: LayoutProp = Layout,
}) => (
<MemoryRouter>
<QueryClientProvider client={new QueryClient()}>
<ThemeProvider theme={theme}>
<StoreContextProvider value={memoryStore()}>
<PreferencesEditorContextProvider>
<AuthContext.Provider value={undefined as any}>
<LayoutProp>
{children}
<Title title="React Admin" />
</LayoutProp>
</AuthContext.Provider>
</PreferencesEditorContextProvider>
</StoreContextProvider>
</ThemeProvider>
</QueryClientProvider>
</MemoryRouter>
);

const Menu = () => (
<MenuList>
<MenuItem>
<ListItemIcon>
<DashboardIcon />
</ListItemIcon>
<ListItemText>Dashboard</ListItemText>
</MenuItem>
<MenuItem>
<ListItemIcon>
<ShoppingCartIcon />
</ListItemIcon>
<ListItemText>Orders</ListItemText>
</MenuItem>
<MenuItem>
<ListItemIcon>
<PeopleIcon />
</ListItemIcon>
<ListItemText>Customers</ListItemText>
</MenuItem>
</MenuList>
);

const BasicLayout = props => <Layout menu={Menu} {...props} />;
export const Basic = () => <Wrapper layout={BasicLayout} />;

const AppBarAlwaysOnLayout = props => <BasicLayout appBarAlwaysOn {...props} />;
export const AppBarAlwaysOn = () => <Wrapper layout={AppBarAlwaysOnLayout} />;
6 changes: 4 additions & 2 deletions packages/ra-ui-materialui/src/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { Inspector } from '../preferences';
export const Layout = (props: LayoutProps) => {
const {
appBar: AppBar = DefaultAppBar,
appBarAlwaysOn,
children,
className,
dashboard,
Expand All @@ -42,9 +43,9 @@ export const Layout = (props: LayoutProps) => {
<StyledLayout className={clsx('layout', className)} {...rest}>
<SkipNavigationButton />
<div className={LayoutClasses.appFrame}>
<AppBar open={open} title={title} />
<AppBar open={open} title={title} alwaysOn={appBarAlwaysOn} />
<main className={LayoutClasses.contentWithSidebar}>
<Sidebar>
<Sidebar appBarAlwaysOn={appBarAlwaysOn}>
<Menu hasDashboard={!!dashboard} />
</Sidebar>
<div id="main-content" className={LayoutClasses.content}>
Expand Down Expand Up @@ -74,6 +75,7 @@ export interface LayoutProps
extends CoreLayoutProps,
Omit<HtmlHTMLAttributes<HTMLDivElement>, 'title'> {
appBar?: ComponentType<AppBarProps>;
appBarAlwaysOn?: boolean;
className?: string;
error?: ComponentType<ErrorProps>;
menu?: ComponentType<MenuProps>;
Expand Down
8 changes: 5 additions & 3 deletions packages/ra-ui-materialui/src/layout/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { useLocale } from 'ra-core';
import { useSidebarState } from './useSidebarState';

export const Sidebar = (props: SidebarProps) => {
const { children, closedSize, size, ...rest } = props;
const { appBarAlwaysOn, children, closedSize, size, ...rest } = props;
const isXSmall = useMediaQuery<Theme>(theme =>
theme.breakpoints.down('sm')
);
Expand All @@ -41,7 +41,9 @@ export const Sidebar = (props: SidebarProps) => {
open={open}
onClose={toggleSidebar}
classes={SidebarClasses}
className={trigger ? SidebarClasses.appBarCollapsed : ''}
className={
trigger && !appBarAlwaysOn ? SidebarClasses.appBarCollapsed : ''
}
{...rest}
>
<div className={SidebarClasses.fixed}>{children}</div>
Expand All @@ -54,9 +56,9 @@ Sidebar.propTypes = {
};

export interface SidebarProps extends DrawerProps {
appBarAlwaysOn?: boolean;
children: ReactElement;
closedSize?: number;

size?: number;
}

Expand Down