Skip to content

Commit

Permalink
Merge pull request #9640 from marmelab/feat/update-docs-for-Breadcrumb
Browse files Browse the repository at this point in the history
[Doc] Update OSS docs for Breadcrumb
  • Loading branch information
djhi committed Feb 5, 2024
2 parents 3dc0e49 + a5545f4 commit cbee14c
Show file tree
Hide file tree
Showing 5 changed files with 198 additions and 40 deletions.
100 changes: 78 additions & 22 deletions docs/Breadcrumb.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ title: "The Breadcrumb Component"

# `<Breadcrumb>`

This [Enterprise Edition](https://marmelab.com/ra-enterprise)<img class="icon" src="./img/premium.svg" /> component renders a breadcrumb path that automatically adapts to the page location. It helps users navigate large web applications.
This [Enterprise Edition](https://marmelab.com/ra-enterprise)<img class="icon" src="./img/premium.svg" /> component renders a breadcrumb path that automatically adapts to the page location. It helps users navigate large web applications.

<video controls autoplay playsinline muted loop width="100%">
<source src="https://marmelab.com/ra-enterprise/modules/assets/ra-navigation/latest/breadcumb-nested-resource.webm" type="video/webm" />
Expand Down Expand Up @@ -38,10 +38,12 @@ export const MyLayout = ({ children, ...rest }) => (
);
```

**Tip**: The layout must be wrapped with `<AppLocationContext>`, as `<Breadcrumb>` reads the app location from this context and not the URL. Layout components from `ra-navigation` ([`<ContainerLayout>`](./ContainerLayout.md) or `<SolarLayout>`) already include that context, so it's not necessary to include it in the custom layout.

**Tip**: The layout must be wrapped with `<AppLocationContext>`, as `<Breadcrumb>` reads the app location from this context and not the URL. Layout components from `ra-navigation` ([`<ContainerLayout>`](./ContainerLayout.md) or `<SolarLayout>`) already include that context, so it's not necessary to include it in the custom layout.

**Tip:** The `ra-enterprise` package exports an alternative `<Layout>`, which contains a pre-configured `<Breadcrumb>` that renders breadcrumb paths for all resources.

Next, set this custom layout as the [`<Admin layout>`](./Admin.md#layout) component:

```jsx
import { Admin } from 'react-admin';
import { DataProvider } from './dataProvider';
Expand Down Expand Up @@ -105,10 +107,10 @@ export const MyLayout = ({ children, ...rest }) => (

With this setup, the breadcrumb on the post pages now renders as:

- "Dashboard / Posts" on the Post List page
- "Dashboard / Posts / Lorem ipsum" on the Post Edition page with id = 1
- "Dashboard / Posts / Lorem ipsum" on the Post Show page with id = 1
- "Dashboard / Posts / Create" on the Post Creation page
- "🏠️ / Posts" on the Post List page
- "🏠️ / Posts / Lorem ipsum" on the Post Edition page with id = 1
- "🏠️ / Posts / Lorem ipsum" on the Post Show page with id = 1
- "🏠️ / Posts / Create" on the Post Creation page

You can customize the breadcrumb path of each page, as well as add custom pages to the breadcrumb, by adding `children` to the `<Breadcrumb>` component. See [the `children` section](#children) below for more information.

Expand All @@ -125,15 +127,23 @@ You don't need to define the app location for CRUD pages as react-admin does it
- Edit: `[resource].edit`. The location also contains the current `record`
- Show: `[resource].show`. The location also contains the current `record`

However, you can customize these default app locations in your CRUD pages, and you must [define the location for custom pages](#adding-custom-pages).
However, you can customize these default app locations in your CRUD pages, and you must [define the location for custom pages](#adding-custom-pages).

To leverage the provided components such as the [`<Breadcrumb>`](#breadcrumb) or [`<MultiLevelMenu>`](./MultiLevelMenu), the layout must be wrapped with `<AppLocationContext>`.

Layout components from `ra-navigation` ([`<ContainerLayout>`](./ContainerLayout) or [`<SolarLayout>`](./SolarLayout)) already include that context, so you can skip that step if you are using one of these layouts.

If, however, you are using the default `<Layout>` component from `react-admin`, or a custom layout, you must wrap it with `<AppLocationContext>`:

## Props

| Prop | Required | Type | Default | Description |
| ----------- | -------- | ------------------- | -------- | -------------------------------------- |
| `children` | Optional | `ReactNode` | - | The Breadcrumb Items to be rendered. |
| `separator` | Optional | `string | function` | ' / ' | The character user as separator |
| `sx` | Optional | `SxProps` | - | Style overrides, powered by MUI System |
| Prop | Required | Type | Default | Description |
| -------------- | -------- | ------------------ | ------- | ------------------------------------------------------------------------------------ |
| `children` | Optional | `ReactNode` | - | The Breadcrumb Items to be rendered. |
| `dashboard` | Optional | `ReactNode` | - | The dashboard component, used to determine if the Admin has a dashboard. |
| `hasDashboard` | Optional | boolean | - | Alternative to `dashboard`. Set to `true` to add a dashboard item to the breadcrumb. |
| `separator` | Optional | string or function | ' / ' | The character user as separator |
| `sx` | Optional | `SxProps` | - | Style overrides, powered by MUI System |

Additional props are passed down to the root `<nav>` component.

Expand Down Expand Up @@ -451,7 +461,51 @@ const MyBreadcrumb = () => (
);
```

Check the [`<Breadcrumb.ResourceItem>`](#breadcrumbresourceitem) section for more information.
Check the [`<Breadcrumb.ResourceItem>`](#breadcrumbresourceitem) section for more information.

## `<Breadcrumb.DashboardItem>`

A version of the `<Breadcrumb.Item>` dedicated to the dashboard.

It is convenient for customizing the dashboard item label.

```tsx
const MyBreadcrumbCustomHome = () => (
<Breadcrumb hasDashboard>
<Breadcrumb.DashboardItem label="My Home">
<Breadcrumb.ResourceItem resource="posts" />
<Breadcrumb.ResourceItem resource="comments" />
</Breadcrumb.DashboardItem>
</Breadcrumb>
);
```

Just like with `<Breadcrumb.Item>`, you can also use a React component as label:

```tsx
import { Breadcrumb } from '@react-admin/ra-navigation';
import { Box, Stack } from '@mui/material';
import { visuallyHidden } from '@mui/utils';
import CabinIcon from '@mui/icons-material/Cabin';

const MyBreadcrumbCustomHome = () => (
<Breadcrumb hasDashboard>
<Breadcrumb.DashboardItem
label={
<Stack direction="row" alignItems="center" spacing={1}>
<CabinIcon />
<Box sx={visuallyHidden}>Dashboard</Box>
</Stack>
}
>
<Breadcrumb.ResourceItem resource="posts" />
<Breadcrumb.ResourceItem resource="comments" />
</Breadcrumb.DashboardItem>
</Breadcrumb>
);
```

**Tip:** It's a good practice to include a visually hidden placeholder ('Dashboard' in this example) for screen readers when using an icon as label.

## Using A Dashboard As The Root

Expand All @@ -474,12 +528,14 @@ export const MyLayout = ({ children, ...rest }) => (

By doing this, the breadcrumb will now show respectively:

- "Dashboard / Posts" on the Post List page
- "Dashboard / Posts / Show #1" on the Post Show page with id = 1
- "Dashboard / Posts / Edit #1" on the Post Edition page with id = 1
- "Dashboard / Posts / Create" on the Post Creation page
- "🏠️ / Posts" on the Post List page
- "🏠️ / Posts / Show #1" on the Post Show page with id = 1
- "🏠️ / Posts / Edit #1" on the Post Edition page with id = 1
- "🏠️ / Posts / Create" on the Post Creation page

**Tip:** Even though it is rendered as a 'home' icon (🏠️), the dashboard breadcrumb item also contains the hidden placeholder text 'Dashboard', for screen readers. If you want to customize this text, e.g. to rename "Dashboard" to "Home", provide a [custom translation](https://marmelab.com/react-admin/Translation.html) for the `ra.page.dashboard` message.

If you want to customize the dashboard breadcrumb item label, e.g. to rename "Dashboard" to "Home", provide a [custom translation](./Translation.md) for the `ra.page.dashboard` message.
If you want to customize the dashboard breadcrumb item label, e.g. to rename "Dashboard" to "Home", provide a [custom translation](./Translation.md) for the `ra.page.dashboard` message.

## Adding Custom Pages

Expand Down Expand Up @@ -604,7 +660,7 @@ const App = () => (

## Nested Resources

When using [nested resources](./Resource.md#nested-resources), you should create breadcrumb items for the sub-resources.
When using [nested resources](./Resource.md#nested-resources), you should create breadcrumb items for the sub-resources.

For instance, the screencast at the top of this page shows a `songs` resource nested in an `artists` resource, using the following routes:

Expand Down Expand Up @@ -838,4 +894,4 @@ const MyBreadcrumb = () => (
);
```
As you see, you can compose Breadcrumb item elements at will.
As you see, you can compose Breadcrumb item elements at will.
38 changes: 33 additions & 5 deletions docs/IconMenu.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ This [Enterprise Edition](https://marmelab.com/ra-enterprise)<img class="icon" s
Your browser does not support the video tag.
</video>

Sometimes, even menus with sub-menus are not enough to organize the navigation. `ra-navigation` offers an alternative UI for that case: a vertical bar with small items, where the menu label renders underneath the icon. Clicking on any of those items opens a panel containing as many navigation links as you like, laid out as you wish.

Test it live on [the Enterprise Edition Storybook](https://storybook.ra-enterprise.marmelab.com/?path=/story/ra-navigation-iconmenu--basic).

## Usage


Create a custom menu component using the `<IconMenu>` and `<IconMenu.Item>` components from the `ra-navigation` package:

```jsx
Expand All @@ -28,15 +31,16 @@ import MusicIcon from '@mui/icons-material/MusicNote';
import PeopleIcon from '@mui/icons-material/People';

const MyMenu = () => (
<IconMenu>
<IconMenu variant="categories">
<IconMenu.Item name="dashboard" to="/" label="Dashboard" icon={<DashboardIcon />} />
<IconMenu.Item name="songs" to="/songs" label="Songs" icon={<MusicIcon />} />
{/* The empty filter is required to avoid falling back to the previously set filter */}
<IconMenu.Item name="artists" to="/artists" label="Artists" icon={<PeopleIcon />} />
</IconMenu>
);
```

Then, create a custom layout using [the `<Layout>` component](./Layout.md) and pass your custom menu component to it. Make sure you wrap the layout with the `<AppLocationContext>` component.
Then, create a custom layout using [the `<Layout>` component](./Layout.md) and pass your custom menu component to it. Make sure you wrap the layout with the `<AppLocationContext>` component.

```jsx
// in src/MyLayout.js
Expand All @@ -52,7 +56,7 @@ export const MyLayout = (props) => (
);
```

`<AppLocationContext>` is necessary because `ra-navigation` doesn't use the URL to detect the current location. Instead, page components *declare* their location using a custom hook (`useDefineAppLocation()`). This allows complex site maps, with multiple levels of nesting. Check [the ra-navigation documentation](https://marmelab.com/ra-enterprise/modules/ra-navigation) to learn more about App Location.
`<AppLocationContext>` is necessary because `ra-navigation` doesn't use the URL to detect the current location. Instead, page components *declare* their location using a custom hook (`useDefineAppLocation()`). This allows complex site maps, with multiple levels of nesting. Check [the ra-navigation documentation](https://marmelab.com/ra-enterprise/modules/ra-navigation) to learn more about App Location.

Finally, pass this custom layout to the `<Admin>` component. You should apply the theme provided by ra-navigation:

Expand All @@ -74,6 +78,30 @@ const App = () => (
);
```

In order to adjust the size of the React-Admin `<Sidebar>` component according to the categories, you should either apply the `theme` provided by the `@react-admin/ra-navigation` package (as above), or merge it in your own custom theme.

```tsx
import merge from 'lodash/merge';
import { defaultTheme } from 'react-admin';
import { ThemeOptions } from '@react-admin/ra-navigation';

export const theme: ThemeOptions = merge({}, defaultTheme, {
sidebar: {
width: 96,
closedWidth: 48,
},
overrides: {
RaSidebar: {
fixed: {
zIndex: 1200,
},
},
},
});
```

**Tip**: With `<IconMenu />`, labels may disappear when the sidebar is in reduced mode. This is because of the internal workings of react-admin. That's why we recommend implementing your own `<AppBar />`, and hiding the Hamburger Button. `<IconMenu />` is thin enough not to interfere with the navigation anyway.

## Props

| Prop | Required | Type | Default | Description |
Expand Down Expand Up @@ -127,7 +155,7 @@ To override the style of `<IconMenu>` using the [application-wide style override
The `<IconMenu.Item>` component displays a menu item with a label and an icon.

```jsx
<IconMenu.Item
<IconMenu.Item
name="dashboard"
to="/"
label="Dashboard"
Expand Down Expand Up @@ -212,7 +240,7 @@ import LabelIcon from '@mui/icons-material/Label';

export const MyMenu = () => {
const resources = useResourceDefinitions();

return (
<IconMenu>
{Object.keys(resources).map(name => (
Expand Down
27 changes: 16 additions & 11 deletions docs/MultiLevelMenu.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ title: "The MultiLevelMenu Component"

# `<MultiLevelMenu>`

This [Enterprise Edition](https://marmelab.com/ra-enterprise)<img class="icon" src="./img/premium.svg" /> component adds support for nested sub menus in the left navigation bar.
This [Enterprise Edition](https://marmelab.com/ra-enterprise)<img class="icon" src="./img/premium.svg" /> component adds support for nested sub menus in the left navigation bar.

![MultiLevelMenu](./img/multilevelmenu.png)

When a React-admin application grows significantly, the default menu might not be the best solution. The `<MultiLevelMenu>` can help unclutter the navigation: it renders a menu with an infinite number of levels and sub-menus. Menu Items that are not at the top level are rendered inside a collapsible panel.

<video controls autoplay playsinline muted loop>
<source src="https://marmelab.com/ra-enterprise/modules/assets/ra-multilevelmenu-item.webm" type="video/webm" />
Expand Down Expand Up @@ -50,7 +54,7 @@ const MyMenu = () => (

Note that each `<MultiLevelMenu.Item>` requires a unique `name` attribute.

Then, create a custom layout using [the `<Layout>` component](./Layout.md) and pass your custom menu component to it. Make sure you wrap the layout with the `<AppLocationContext>` component.
Then, create a custom layout using [the `<Layout>` component](./Layout.md) and pass your custom menu component to it. Make sure you wrap the layout with the `<AppLocationContext>` component.

```jsx
// in src/MyLayout.js
Expand All @@ -66,7 +70,7 @@ export const MyLayout = (props) => (
);
```

`<AppLocationContext>` is necessary because `ra-navigation` doesn't use the URL to detect the current location. Instead, page components *declare* their location using a custom hook (`useDefineAppLocation()`). This allows complex site maps, with multiple levels of nesting. That's the reason why each `<MultiLevelMenu.Item>` requires a unique `name`, that matches a particular page location.
`<AppLocationContext>` is necessary because `ra-navigation` doesn't use the URL to detect the current location. Instead, page components *declare* their location using a custom hook (`useDefineAppLocation()`). This allows complex site maps, with multiple levels of nesting. That's the reason why each `<MultiLevelMenu.Item>` requires a unique `name`, that matches a particular page location.

You can set the `AppLocation` for a given page like so:

Expand All @@ -89,7 +93,7 @@ And then use this `AppLocation` as `name` for `<MultiLevelMenu.Item>`:
>
```

Check [the ra-navigation documentation](https://marmelab.com/ra-enterprise/modules/ra-navigation) to learn more about App Location.
Check [the ra-navigation documentation](https://marmelab.com/ra-enterprise/modules/ra-navigation) to learn more about App Location.

Finally, pass this custom layout to the `<Admin>` component

Expand All @@ -111,11 +115,12 @@ const App = () => (

## Props

| Prop | Required | Type | Default | Description |
| ------------- | -------- | ----------- | -------- | -------------------------------------- |
| `children` | Optional | `ReactNode` | - | The Menu Items to be rendered. |
| `initialOpen` | Optional | `boolean` | `false` | Whether the menu is initially open. |
| `sx` | Optional | `SxProps` | - | Style overrides, powered by MUI System |
| Prop | Required | Type | Default | Description |
| -------------- | -------- | ----------- | -------- | ------------------------------------------------------------- |
| `children` | Optional | `ReactNode` | - | The Menu Items to be rendered. |
| `initialOpen` | Optional | `boolean` | `false` | Whether the menu is initially open. |
| `openItemList` | Optional | `Array` | - | List of names of menu items that should be opened by default. |
| `sx` | Optional | `SxProps` | - | Style overrides, powered by MUI System |

Additional props are passed down to the root `<div>` component.

Expand Down Expand Up @@ -175,7 +180,7 @@ To override the style of `<MultiLevelMenu>` using the [application-wide style ov
The `<MultiLevelMenu.Item>` component displays a menu item with a label and an icon.

```jsx
<MultiLevelMenu.Item
<MultiLevelMenu.Item
name="dashboard"
to="/"
label="Dashboard"
Expand Down Expand Up @@ -210,7 +215,7 @@ import LabelIcon from '@mui/icons-material/Label';

export const MyMenu = () => {
const resources = useResourceDefinitions();

return (
<MultiLevelMenu>
{Object.keys(resources).map(name => (
Expand Down
Binary file added docs/img/multilevelmenu.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit cbee14c

Please sign in to comment.