diff --git a/docs/AppBar.md b/docs/AppBar.md index e00284794fd..efd2099fb8f 100644 --- a/docs/AppBar.md +++ b/docs/AppBar.md @@ -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 | @@ -73,17 +72,6 @@ const App = () => ( Additional props are passed to [the underlying MUI `` 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 = () => ; -``` - ## `children` The `` 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. diff --git a/docs/Layout.md b/docs/Layout.md index 3b3362942bb..9f6a8fc50a4 100644 --- a/docs/Layout.md +++ b/docs/Layout.md @@ -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 `
` 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 `
` 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 `` props: @@ -114,6 +116,18 @@ export const MyAppBar = () => ( Check out the [`` 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) => ; +``` + ## `className` `className` is passed to the root `
` component. It lets you style the layout with CSS - but the `sx` prop is preferred. diff --git a/packages/ra-ui-materialui/src/layout/AppBar.stories.tsx b/packages/ra-ui-materialui/src/layout/AppBar.stories.tsx index ddb4d5fb63c..1664dd224da 100644 --- a/packages/ra-ui-materialui/src/layout/AppBar.stories.tsx +++ b/packages/ra-ui-materialui/src/layout/AppBar.stories.tsx @@ -74,12 +74,6 @@ export const Color = () => ( ); -export const AlwaysOn = () => ( - - - -); - export const Position = () => ( diff --git a/packages/ra-ui-materialui/src/layout/AppBar.tsx b/packages/ra-ui-materialui/src/layout/AppBar.tsx index 063db0d638a..58fbd6ce63f 100644 --- a/packages/ra-ui-materialui/src/layout/AppBar.tsx +++ b/packages/ra-ui-materialui/src/layout/AppBar.tsx @@ -126,6 +126,11 @@ AppBar.propTypes = { const DefaultUserMenu = ; export interface AppBarProps extends Omit { + /** + * 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 `` instead. + */ alwaysOn?: boolean; container?: React.ElementType; /** diff --git a/packages/ra-ui-materialui/src/layout/Layout.stories.tsx b/packages/ra-ui-materialui/src/layout/Layout.stories.tsx new file mode 100644 index 00000000000..9749f2aeb2b --- /dev/null +++ b/packages/ra-ui-materialui/src/layout/Layout.stories.tsx @@ -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 = () => ( + + + + +); + +const Wrapper = ({ + children = , + theme = createTheme(defaultTheme), + layout: LayoutProp = Layout, +}) => ( + + + + + + + + {children} + + </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} />; diff --git a/packages/ra-ui-materialui/src/layout/Layout.tsx b/packages/ra-ui-materialui/src/layout/Layout.tsx index 63b1aa76ccf..d98600b2c09 100644 --- a/packages/ra-ui-materialui/src/layout/Layout.tsx +++ b/packages/ra-ui-materialui/src/layout/Layout.tsx @@ -21,6 +21,7 @@ import { Inspector } from '../preferences'; export const Layout = (props: LayoutProps) => { const { appBar: AppBar = DefaultAppBar, + appBarAlwaysOn, children, className, dashboard, @@ -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}> @@ -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>; diff --git a/packages/ra-ui-materialui/src/layout/Sidebar.tsx b/packages/ra-ui-materialui/src/layout/Sidebar.tsx index 888e5f94426..9fda8d89444 100644 --- a/packages/ra-ui-materialui/src/layout/Sidebar.tsx +++ b/packages/ra-ui-materialui/src/layout/Sidebar.tsx @@ -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') ); @@ -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> @@ -54,9 +56,9 @@ Sidebar.propTypes = { }; export interface SidebarProps extends DrawerProps { + appBarAlwaysOn?: boolean; children: ReactElement; closedSize?: number; - size?: number; }