diff --git a/docs/AuthRBAC.md b/docs/AuthRBAC.md index 9e5be99ad3e..11e0224a74b 100644 --- a/docs/AuthRBAC.md +++ b/docs/AuthRBAC.md @@ -630,7 +630,7 @@ const ProductShow = () => ( ### `` -Replacement for the show `` that only renders a tab if the user has the right permissions. +Replacement for the `` that only renders a tab if the user has the right permissions. Add a `name` prop to the Tab to define the resource on which the user needs to have the 'read' permissions for. diff --git a/docs/Permissions.md b/docs/Permissions.md index 788a4e083a3..d0393a5ce95 100644 --- a/docs/Permissions.md +++ b/docs/Permissions.md @@ -178,14 +178,14 @@ export const UserEdit = () => { return ( }> - + {permissions === 'admin' && } - + {permissions === 'admin' && - + - } + } ); diff --git a/docs/Show.md b/docs/Show.md index a6255d24825..8e7e9c031f6 100644 --- a/docs/Show.md +++ b/docs/Show.md @@ -80,12 +80,12 @@ export const PostShow = () => ( - + -+ -+ ++ - + @@ -362,25 +362,25 @@ export const PostShow = () => { ``` {% endraw %} -This also works inside a `TabbedShowLayout`, and you can hide a `Tab` completely: +This also works inside a ``, and you can hide a `TabbedShowLayout.Tab` completely: {% raw %} ```jsx -import { Show, TabbedShowLayout, Tab, TextField } from 'react-admin'; +import { Show, TabbedShowLayout, TextField } from 'react-admin'; export const UserShow = () => { const { permissions } = usePermissions(); return ( - + {permissions === 'admin' && } - + {permissions === 'admin' && - + - } + } ); diff --git a/docs/ShowTutorial.md b/docs/ShowTutorial.md index 708025f1ebe..92e720c64ba 100644 --- a/docs/ShowTutorial.md +++ b/docs/ShowTutorial.md @@ -358,7 +358,7 @@ const BookShow = () => ( When a Show view has to display a lot of fields, the `` component ends up in very long page that is not user-friendly. You can use [the `` component](./TabbedShowLayout.md) instead, which is a variant of the `` component that displays the fields in tabs. ```jsx -import { Show, TabbedShowLayout, Tab, TextField, DateField, WithRecord } from 'react-admin'; +import { Show, TabbedShowLayout, TextField, DateField, WithRecord } from 'react-admin'; import StarIcon from '@mui/icons-material/Star'; import FavoriteIcon from '@mui/icons-material/Favorite'; import PersonPinIcon from '@mui/icons-material/PersonPin'; @@ -366,19 +366,19 @@ import PersonPinIcon from '@mui/icons-material/PersonPin'; const BookShow = () => ( - }> + }> - - }> + + }> <> {[...Array(record.rating)].map((_, index) => )} } /> - + ); diff --git a/docs/TabbedForm.md b/docs/TabbedForm.md index dee331d1053..2e199a124e5 100644 --- a/docs/TabbedForm.md +++ b/docs/TabbedForm.md @@ -5,7 +5,7 @@ title: "TabbedForm" # `` -`` creates a `
` to edit a record, and renders inputs grouped by tab. The tabs are set by using `` components. It is useful for forms with a lot of inputs, to reduce the time taken to change a subset of the fields. +`` creates a `` to edit a record, and renders inputs grouped by tab. The tabs are set by using `` components. It is useful for forms with a lot of inputs, to reduce the time taken to change a subset of the fields. ![tabbed form](./img/tabbed-form.gif) @@ -13,14 +13,13 @@ title: "TabbedForm" `` reads the `record` from the `RecordContext`, uses it to initialize the defaultValues of a ``, renders its children in a MUI ``, and renders a toolbar with a `` that calls the `save` callback prepared by the edit or the create controller when pressed. -`` is often used as child of `` or ``. It accepts `` elements as children. It relies on [react-hook-form](https://react-hook-form.com/) for form handling. It requires no prop by default. +`` is often used as child of `` or ``. It accepts `` elements as children. It relies on [react-hook-form](https://react-hook-form.com/) for form handling. It requires no prop by default. {% raw %} ```jsx import * as React from "react"; import { TabbedForm, - FormTab, Edit, Datagrid, TextField, @@ -36,22 +35,22 @@ import { export const PostEdit = () => ( - + - - + + - - + + - - + + @@ -59,7 +58,7 @@ export const PostEdit = () => ( - + ); @@ -187,7 +186,7 @@ export const PostCreate = () => ( ``` {% endraw %} -**Tip:** If you want to customize the _content_ of the tabs instead, for example to limit the width of the form, you should rather add an `sx` prop to the [`` component](#formtab). +**Tip:** If you want to customize the _content_ of the tabs instead, for example to limit the width of the form, you should rather add an `sx` prop to the [`` component](#formtab). ## `sanitizeEmptyValues` @@ -241,22 +240,22 @@ However, this makes `` impossible to use in pages where the state is export const PostEdit = () => ( - + - - + + - - + + - - + + @@ -264,18 +263,18 @@ export const PostEdit = () => ( - + ); ``` {% endraw %} -**Tip**: When `syncWithLocation` is `false`, the `path` prop of the `` components is ignored. +**Tip**: When `syncWithLocation` is `false`, the `path` prop of the `` components is ignored. ## `tabs` -By default, `` uses ``, an internal react-admin component, to renders the tab headers. You can pass a custom component as the `tabs` prop to tweak th UX of these headers. Besides, props from `` are passed down to MUI's `` component. +By default, `` uses ``, an internal react-admin component, to render the tab headers. You can pass a custom component as the `tabs` prop to tweak th UX of these headers. Besides, props from `` are passed down to MUI's `` component. The following example shows how to make use of scrollable ``. Pass `variant="scrollable"` and `scrollButtons="auto"` props to `` and use it in the `tabs` prop from ``. @@ -470,16 +469,16 @@ export const TagEdit = () => ( **Warning**: This feature only works if you have a dependency on react-router 6.3.0 **at most**. The react-router team disabled this possibility in react-router 6.4, so `warnWhenUnsavedChanges` will silently fail with react-router 6.4 or later. -## `` +## `` -`` expect `` elements as children. `` elements accept four props: +`` expect `` elements as children. `` elements accept four props: - `label`: the label of the tab - `path`: the path of the tab in the URL (ignored when `syncWithLocation={false}`) - `sx`: custom styles to apply to the tab - `children`: the content of the tab (usually a list of inputs) -`` renders its children in a MUI `` component, i.e. one child per row. +`` renders its children in a MUI `` component, i.e. one child per row. The `sx` prop allows to style the content of the tab, e.g. to limit its width: @@ -488,12 +487,12 @@ The `sx` prop allows to style the content of the tab, e.g. to limit its width: const ProductEdit = () => ( }> - ... - + ); @@ -506,25 +505,25 @@ React-admin passes the `label` through the `translate()` function, so you can us const ProductEdit = () => ( }> - + ... - - + + ... - - + + ... - + ); ``` -**Tip**: React-admin renders each tab *twice*: once to get the tab header, and once to get the tab content. If you use a custom component instead of a ``, make sure that it accepts an `intent` prop, and renders differently when the value of that prop is 'header' or 'content'. +**Tip**: React-admin renders each tab *twice*: once to get the tab header, and once to get the tab content. If you use a custom component instead of a ``, make sure that it accepts an `intent` prop, and renders differently when the value of that prop is 'header' or 'content'. -## Using Fields As FormTab Children +## Using Fields As Children -The basic usage of `` is to pass [Input components](./Inputs.md) as children of ``. For non-editable fields, you can pass `disabled` inputs, or even [Field components](./Fields.md). But since `` components have no label by default, you'll have to wrap your inputs in a `` component in that case: +The basic usage of `` is to pass [Input components](./Inputs.md) as children of ``. For non-editable fields, you can pass `disabled` inputs, or even [Field components](./Fields.md). But since `` components have no label by default, you'll have to wrap your inputs in a `` component in that case: ```jsx import { Edit, TabbedForm, TextInput, Labeled, TextField } from 'react-admin'; @@ -532,13 +531,13 @@ import { Edit, TabbedForm, TextInput, Labeled, TextField } from 'react-admin'; const PostEdit = () => ( - + - + ); @@ -550,25 +549,25 @@ const PostEdit = () => ( ![complex form layout](./img/TabbedForm-layout.png) -By default, `` renders one child per row. But a given child can be a layout element (e.g. ``, ``, ``) and contain several input elements. This lets you build form layouts of any complexity: +By default, `` renders one child per row. But a given child can be a layout element (e.g. ``, ``, ``) and contain several input elements. This lets you build form layouts of any complexity: {% raw %} ```jsx const ProductEdit = () => ( }> - + ... - - + + - - + + ... - - + + ... - + ); @@ -637,7 +636,7 @@ const ProductEditDetails = () => ( ![dynamic tab label](./img/FormTab-dynamic-label.png) -To achieve that, create a custom commponent that renders a `` with a dynamic `label`: +To achieve that, create a custom commponent that renders a `` with a dynamic `label`: ```jsx const ReviewsFormTab = props => { @@ -657,7 +656,7 @@ const ReviewsFormTab = props => { if (!isLoading) { label += ` (${total})`; } - return ; + return ; }; ``` @@ -668,15 +667,15 @@ Then, use this custom component in a ``: const ProductEdit = () => ( }> - + ... - - + + ... - - + + ... - + { return ( - + ... - + {permissions === 'admin' && - + ... - + } diff --git a/docs/TabbedShowLayout.md b/docs/TabbedShowLayout.md index 485dd077dfb..0922456cfe0 100644 --- a/docs/TabbedShowLayout.md +++ b/docs/TabbedShowLayout.md @@ -5,39 +5,39 @@ title: "TabbedShowLayout" # `` -The `` pulls the `record` from the `RecordContext`. It renders a set of ``, each of which contains a list of record fields in a single-column layout (via MUI's `` component). `` delegates the actual rendering of fields to its children, which should be `` components. `` wraps each field inside a `` component to add a label. +The `` pulls the `record` from the `RecordContext`. It renders a set of ``, each of which contains a list of record fields in a single-column layout (via MUI's `` component). `` delegates the actual rendering of fields to its children, which should be `` elements. `` wraps each field inside a `` component to add a label. -Switching tabs will update the current url. By default, it uses the tabs indexes and the first tab will be displayed at the root url. You can customize the path by providing a `path` prop to each `Tab` component. If you'd like the first one to act as an index page, just omit the `path` prop. +Switching tabs will update the current url. By default, it uses the tabs indexes and the first tab will be displayed at the root url. You can customize the path by providing a `path` prop to each `` component. If you'd like the first one to act as an index page, just omit the `path` prop. ![tabbed show](./img/tabbed-show.gif) ## Usage -Use `` as descendant of a `` component (or any component creating a ``), define the tabs via `` children, and set the fields to be displayed as children of each tab: +Use `` as descendant of a `` component (or any component creating a ``), define the tabs via `` children, and set the fields to be displayed as children of each tab: {% raw %} ```jsx -import { Show, TabbedShowLayout, Tab } from 'react-admin' +import { Show, TabbedShowLayout } from 'react-admin' export const PostShow = () => ( - + - - + + - - + + - - + + @@ -45,7 +45,7 @@ export const PostShow = () => ( - + ); @@ -67,9 +67,9 @@ Additional props are passed to the root component (`
`). ## Tabs -Children of `` must be `` components. +Children of `` must be `` components. -The `` component renders tabs headers and the active tab. It manages the tab change, either via the URL, or an internal state. +The `` component renders tabs headers and the active tab. It manages the tab change, either via the URL, or an internal state. It accepts the following props: @@ -82,18 +82,18 @@ It accepts the following props: import * as React from "react"; import FavoriteIcon from '@mui/icons-material/Favorite'; import PersonPinIcon from '@mui/icons-material/PersonPin'; -import { Show, TabbedShowLayout, Tab, TextField } from 'react-admin'; +import { Show, TabbedShowLayout, TextField } from 'react-admin'; export const PostShow = () => ( - }> + }> - - } path="metadata"> + + } path="metadata"> - + ); @@ -101,15 +101,15 @@ export const PostShow = () => ( ## Tab Fields -`` renders each child inside a `` component. This component uses the humanized source as label by default. You can customize it by passing a `label` prop to the fields: +`` renders each child inside a `` component. This component uses the humanized source as label by default. You can customize it by passing a `label` prop to the fields: ```jsx const PostShow = () => ( - + - + ); @@ -122,10 +122,10 @@ The `` uses the humanized source by default. You can customize it const PostShow = () => ( - + - + ); @@ -151,15 +151,15 @@ You can disable the `` decoration by passing setting `label={false}` on const PostShow = () => ( - + - + ); ``` -`` children can be anything you want. Try passing your own components: +`` children can be anything you want. Try passing your own components: ```jsx const PostTitle = () => { @@ -170,9 +170,9 @@ const PostTitle = () => { const PostShow = () => ( - + - + ); @@ -189,22 +189,22 @@ import { TabbedShowLayout, Tab } from 'react-admin' export const PostShow = () => ( - + - - + + - - + + - - + + @@ -212,26 +212,26 @@ export const PostShow = () => ( - + ); ``` {% endraw %} -**Tip**: When `syncWithLocation` is `false`, the `path` prop of the `` components is ignored. +**Tip**: When `syncWithLocation` is `false`, the `path` prop of the `` components is ignored. ## Spacing -`` renders a MUI ``. You can customize the spacing of each row by passing a `spacing` prop: +`` renders a MUI ``. You can customize the spacing of each row by passing a `spacing` prop: ```jsx const PostShow = () => ( - + - + ); @@ -249,9 +249,9 @@ import { Divider } from '@mui/material'; const PostShow = () => ( }> - + - + ); @@ -289,9 +289,9 @@ By default, `` reads the record from the `ResourceContext`. Bu ```jsx const StaticPostShow = () => ( - + - + ); ``` @@ -309,7 +309,7 @@ The `` component accepts the usual `className` prop but you ca To override the style of all instances of `` using the [MUI style overrides](https://mui.com/customization/theme-components/), use the `RaTabbedShowLayout` key. -To style the tabs, the `` component accepts two props: +To style the tabs, the `` component accepts two props: - `className` is passed to the tab *header* - `contentClassName` is passed to the tab *content* @@ -318,16 +318,16 @@ To style the tabs, the `` component accepts two props: * [Field components](./Fields.md) * [Show Guesser](./ShowGuesser.md) guesses the fields based on the record type -* [SimpleShowLayout](./SimpleShowLayout.md) provides a simpler layout with no tabs +* [SimpleShowLayout](./TabbedShowLayout.md) provides a simpler layout with no tabs ## API * [``] -* [``] +* [``] * [``] * [`useRecordContext`] [``]: https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/Labeled.tsx [``]: https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/detail/TabbedShowLayout.tsx -[``]: https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/detail/Tab.tsx +[``]: https://github.com/marmelab/react-admin/blob/master/packages/ra-ui-materialui/src/detail/Tab.tsx [`useRecordContext`]: https://github.com/marmelab/react-admin/blob/master/packages/ra-core/src/controller/record/useRecordContext.ts diff --git a/examples/demo/src/products/ProductCreate.tsx b/examples/demo/src/products/ProductCreate.tsx index fd81586a80c..d7767832b76 100644 --- a/examples/demo/src/products/ProductCreate.tsx +++ b/examples/demo/src/products/ProductCreate.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { Create, FormTab, TabbedForm, TextInput, required } from 'react-admin'; +import { Create, TabbedForm, TextInput, required } from 'react-admin'; import { RichTextInput } from 'ra-input-rich-text'; import { ProductEditDetails } from './ProductEditDetails'; @@ -8,7 +8,7 @@ const ProductCreate = () => { return ( - @@ -23,20 +23,20 @@ const ProductCreate = () => { fullWidth validate={required()} /> - - + - - + - + ); diff --git a/examples/demo/src/products/ProductEdit.tsx b/examples/demo/src/products/ProductEdit.tsx index bdec376bdef..fa161df6790 100644 --- a/examples/demo/src/products/ProductEdit.tsx +++ b/examples/demo/src/products/ProductEdit.tsx @@ -4,7 +4,6 @@ import { DateField, Edit, EditButton, - FormTab, Pagination, ReferenceManyField, required, @@ -31,28 +30,28 @@ const ProductTitle = () => { const ProductEdit = () => ( }> - - - + - - + - + { if (!isLoading) { label += ` (${total})`; } - return ; + return ; }; export default ProductEdit; diff --git a/examples/simple/src/posts/PostEdit.tsx b/examples/simple/src/posts/PostEdit.tsx index 8e54a888866..3f920215c3f 100644 --- a/examples/simple/src/posts/PostEdit.tsx +++ b/examples/simple/src/posts/PostEdit.tsx @@ -14,7 +14,6 @@ import { CreateButton, ShowButton, EditButton, - FormTab, ImageField, ImageInput, NumberInput, @@ -107,7 +106,7 @@ const PostEdit = () => { defaultValues={{ average_note: 0 }} warnWhenUnsavedChanges > - + { )} - - + + - - + + { - - + + { - + ); diff --git a/examples/simple/src/posts/PostShow.tsx b/examples/simple/src/posts/PostShow.tsx index a06642cee1e..fb94597cab5 100644 --- a/examples/simple/src/posts/PostShow.tsx +++ b/examples/simple/src/posts/PostShow.tsx @@ -15,7 +15,6 @@ import { ShowContextProvider, ShowView, SingleFieldList, - Tab, TabbedShowLayout, TextField, UrlField, @@ -43,7 +42,7 @@ const PostShow = () => { }> - + {controllerProps.record && @@ -57,15 +56,15 @@ const PostShow = () => { - - + + - - + + { - - + + { - + diff --git a/examples/simple/src/users/UserCreate.tsx b/examples/simple/src/users/UserCreate.tsx index 51b6459e89e..7621a203c9e 100644 --- a/examples/simple/src/users/UserCreate.tsx +++ b/examples/simple/src/users/UserCreate.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import { useFormContext } from 'react-hook-form'; import { Create, - FormTab, SaveButton, AutocompleteInput, TabbedForm, @@ -61,16 +60,16 @@ const UserCreate = () => { warnWhenUnsavedChanges toolbar={} > - + - + {permissions === 'admin' && ( - + { ]} validate={[required()]} /> - + )} diff --git a/examples/simple/src/users/UserEdit.tsx b/examples/simple/src/users/UserEdit.tsx index 232fca45506..1e849e4e026 100644 --- a/examples/simple/src/users/UserEdit.tsx +++ b/examples/simple/src/users/UserEdit.tsx @@ -4,7 +4,6 @@ import { CloneButton, DeleteWithConfirmButton, Edit, - FormTab, required, SaveButton, SelectInput, @@ -64,16 +63,16 @@ const UserEditForm = ({ save, ...props }: { save?: any }) => { {...props} onSubmit={newSave} > - + {permissions === 'admin' && } - + {permissions === 'admin' && ( - + { ]} defaultValue={'user'} /> - + )} ); diff --git a/examples/simple/src/users/UserShow.tsx b/examples/simple/src/users/UserShow.tsx index ee97277ea58..28a75a666a7 100644 --- a/examples/simple/src/users/UserShow.tsx +++ b/examples/simple/src/users/UserShow.tsx @@ -1,12 +1,6 @@ /* eslint react/jsx-key: off */ import * as React from 'react'; -import { - Show, - Tab, - TabbedShowLayout, - TextField, - usePermissions, -} from 'react-admin'; +import { Show, TabbedShowLayout, TextField, usePermissions } from 'react-admin'; import Aside from './Aside'; @@ -15,14 +9,17 @@ const UserShow = () => { return ( - + - + {permissions === 'admin' && ( - + - + )}