diff --git a/docs/Features.md b/docs/Features.md index 57db5de0564..5bb4c68d488 100644 --- a/docs/Features.md +++ b/docs/Features.md @@ -864,6 +864,7 @@ export const CategoriesList = () => ( Check out the following components for displaying hierarchical data: - [``](./TreeWithDetails.md): A list view for tree structures, with a details panel. +- [``](./TreeInput.md): An input component for tree structures. - [``](https://marmelab.com/ra-enterprise/modules/ra-tree#tree-component): A list view for tree structures, with a Material UI skin. ## Application Building Blocks diff --git a/docs/Inputs.md b/docs/Inputs.md index 51dcef8fd98..9b3f3b3ca71 100644 --- a/docs/Inputs.md +++ b/docs/Inputs.md @@ -75,14 +75,13 @@ React-admin provides a set of Input components, each one designed for a specific | Date & time | `'2022-10-24T19:40:28.003Z'` | [``](./DateTimeInput.md) | | Object | `{ foo: 'bar' }` | All inputs (see [ `source`](#source)) | | Enum | `'foo'` | [``](./SelectInput.md), [``](./AutocompleteInput.md), [``](./RadioButtonGroupInput.md) | +| Tree node | `42` | [``](./TreeInput.md) | | Foreign key | `42` | [``](./ReferenceInput.md) | | Array of objects | `[{ item: 'jeans', qty: 3 }, { item: 'shirt', qty: 1 }]` | [``](./ArrayInput.md) | | Array of Enums | `['foo', 'bar']` | [``](./SelectArrayInput.md), [``](./AutocompleteArrayInput.md), [``](./CheckboxGroupInput.md), [``](./DualListInput.md) | | Array of foreign keys | `[42, 43]` | [``](./ReferenceArrayInput.md) | | Translations | `{ en: 'Hello', fr: 'Bonjour' }` | [``](./TranslatableInputs.md) | -| Related records | `[{ id: 42, title: 'Hello' }, { id: 43, title: 'World' }]` | [``](./ReferenceManyInput.md), [``](./ReferenceManyToManyInput.md), [``](./ReferenceOneInput.md) | - - +| Related records | `[{ id: 42, title: 'Hello' }, { id: 43, title: 'World' }]` | [``](./ReferenceManyInput.md), [``](./ReferenceManyToManyInput.md), [``](./ReferenceNodeInput.md), [``](./ReferenceOneInput.md) | ## `className` diff --git a/docs/Reference.md b/docs/Reference.md index 9624bc92bd8..b64a9ce5170 100644 --- a/docs/Reference.md +++ b/docs/Reference.md @@ -135,6 +135,7 @@ title: "Index" * [``](./ReferenceManyInput.md) * [``](./ReferenceManyToManyField.md) * [``](./ReferenceManyToManyInput.md) +* [``](./ReferenceNodeInput.md) * [``](./ReferenceOneField.md) * [``](./ReferenceOneInput.md) * [``](./Resource.md) @@ -181,6 +182,7 @@ title: "Index" * [``](./TranslatableFields.md) * [``](./TranslatableInputs.md) * [``](https://marmelab.com/ra-enterprise/modules/ra-tree#tree-component) +* [``](./TreeInput.md) * [``](./TreeWithDetails.md) * [``](./Toolbar.md) diff --git a/docs/ReferenceInput.md b/docs/ReferenceInput.md index bcc16228b11..4c29403ff4f 100644 --- a/docs/ReferenceInput.md +++ b/docs/ReferenceInput.md @@ -341,6 +341,37 @@ const filterToQuery = searchText => ({ name_ilike: `%${searchText}%` }); ``` +## Tree Structure + +If the reference resource is a tree, use [``](./ReferenceNodeInput.md) instead of ``. + + + +For instance, to edit the category of a product and let the user choose the category in a tree: + +```tsx +import { Edit, SimpleForm, TextInput } from 'react-admin'; +import { ReferenceNodeInput } from '@react-admin/ra-tree'; + +const ProductEdit = () => ( + + + + + + + +); +``` + + ## Performance Why does `` use the `dataProvider.getMany()` method with a single value `[id]` instead of `dataProvider.getOne()` to fetch the record for the current value? diff --git a/docs/ReferenceNodeInput.md b/docs/ReferenceNodeInput.md new file mode 100644 index 00000000000..35285e350af --- /dev/null +++ b/docs/ReferenceNodeInput.md @@ -0,0 +1,113 @@ +--- +layout: default +title: "The ReferenceNodeInput Component" +--- + +# `` Component + +This [Enterprise Edition](https://marmelab.com/ra-enterprise) component allows users to select one or several nodes from a tree of a reference resource. For instance, this is useful to select a category for a product. + + + +## Usage + +Use `` in a react-admin form, and set the `reference` and `source` props just like for a ``. + +```tsx +import { Edit, SimpleForm, TextInput } from 'react-admin'; +import { ReferenceNodeInput } from '@react-admin/ra-tree'; + +const ProductEdit = () => ( + + + + + + +); +``` + +`` is a controller component, i.e. it fetches the tree from the reference resource, creates a tree choices context, and renders its child component. + +By default `` will render a simple [``](./TreeInput.md) as its child. If you need to customize the `` props, e.g. set the `multiple` prop, you will need to pass the child explicitly: + +```tsx +import { Edit, SimpleForm, TextInput } from 'react-admin'; +import { ReferenceNodeInput, TreeInput } from '@react-admin/ra-tree'; + +const ProductEdit = () => ( + + + + + + + + +); +``` + + + +## Props + +| Prop | Required | Type | Default | Description | +| ----------------- | ------------ | ---------------- | --------------- | ----------------------------------------------------------------------------------------- | +| `reference` | Required | string | - | The reference resource | +| `source` | Required | string | - | The name of the source field | +| `children` | Optional | React Element | `` | The child component responsible for rendering the input | +| `meta` | Optional | object | - | An object containing metadata to be passed when calling the dataProvider | + +## `children` + +`` accepts only one child, which is responsible for rendering the input. By default, it renders a simple `` with no props. If you need to pass additional props to ``, you will need to pass them explicitely: + +```tsx + + + +``` + +## `meta` + +Use the `meta` prop to pass metadata to the dataProvider when calling `getTree()`: + +{% raw %} +```tsx + +``` +{% endraw %} + +## `reference` + +Use the `reference` prop to specify the reference resource: + +```tsx + +``` + +## `source` + +Use the `source` prop to specify the name of the source field: + +```tsx + +``` diff --git a/docs/SelectInput.md b/docs/SelectInput.md index 18a5239041b..ffb5c2aea39 100644 --- a/docs/SelectInput.md +++ b/docs/SelectInput.md @@ -712,3 +712,40 @@ const CreateCategory = () => { }; ``` {% endraw %} + +## Tree Structure + +If the choices form a hierarchy or a tree, use the [``](./TreeInput.md) component instead of ``. It renders a collapsible tree structure, and lets users select a value by clicking on a node. + + + +```tsx +import { Edit, SimpleForm, TextInput } from 'react-admin'; +import { TreeInput } from '@react-admin/ra-tree'; + +export const ProductEdit = () => ( + + + + + + + +); +``` \ No newline at end of file diff --git a/docs/TreeInput.md b/docs/TreeInput.md new file mode 100644 index 00000000000..6d501c46483 --- /dev/null +++ b/docs/TreeInput.md @@ -0,0 +1,189 @@ +--- +layout: default +title: "The TreeInput Component" +--- + +# `` Component + +This [Enterprise Edition](https://marmelab.com/ra-enterprise) component allows to select one or several nodes from a tree. + + + +## Usage + +Use `` in a react-admin form, and pass the possible choices as the `treeData` prop . It must be an array of nodes with a `children` field. + +```tsx +import { Edit, SimpleForm, TextInput } from 'react-admin'; +import { TreeInput } from '@react-admin/ra-tree'; + +export const ProductEdit = () => ( + + + + + + + +); +``` + +**Tip:** You can use the `` component in a [``](./ReferenceNodeInput.md) to automatically fetch the `treeData` from a reference resource. + +`` uses rc-tree's [`` component](https://tree-react-component.vercel.app/#tree-props) under the hood, and accepts all its props. + +## Props + +| Prop | Required | Type | Default | Description | +| ----------------- | ------------ | ---------------- | --------- | ----------------------------------------------------------------------------------------- | +| `source` | Required | string | - | The name of the source field. Required unless when used inside `` | +| `treeData` | Required | array of objects | - | The tree data | +| `multiple` | Optional | boolean | `false` | Set to true to allow selecting multiple nodes | +| `hideRootNodes` | Optional | boolean | `false` | Set to true to hide all root nodes | +| `titleField` | Optional | string | `'title'` | The name of the field holding the node title | + +`` also accepts the [common input props](./Inputs.md#common-input-props) and the [rc-tree](https://tree-react-component.vercel.app/) props. + +## `checkStrictly` + +By default, `` uses the `checkStrictly` prop from rc-tree's [`` component](https://tree-react-component.vercel.app/#tree-props) to allow selecting leaf and parent nodes independently. If you want to disable this feature, you can set the `checkStrictly` prop to `false`: + +```tsx + +``` + +## `hideRootNodes` + +Use the `hideRootNodes` prop to hide all root nodes: + +```tsx + +``` + +## `multiple` + +Use the `multiple` prop to allow selecting multiple nodes. In that case, `` renders a tree with one checkbox per line. + + + + +```tsx +import { SimpleForm } from 'react-admin'; +import { TreeInput } from '@react-admin/ra-tree'; +import treeData from './treeData'; + +export const SimpleTreeForm = () => ( + + + +); +``` + +## `titleField` + +Use the `titleField` prop to specify the name of the field holding the node title: + +```tsx + +``` + +## `treeData` + +The list of possible choices must be passed as the `treeData` prop. It must be an array of nodes with a `children` field. + +```tsx + +``` + +If you need to fetch the `treeData`, you're probably editing a relationship. In that case, you should use the [``](./ReferenceNodeInput.md) component, which fetches the `treeData` from a reference resource on mount . + +## Fetching Choices + +You can use `dataProvider.getTree()` to fetch choices. For example, to fetch a list of categories for a product: + +```tsx +import { useGetTree, TreeInput } from '@react-admin/ra-tree'; + +const CategoryInput = () => { + const { isLoading, data: tree } = useGetTree('categories'); + if (isLoading) return ; + return ( + + ); +}; +``` + +The `isLoading` prop is used to display a loading indicator while the data is being fetched. + +However, most of the time, if you need to populate a `` with choices fetched from another resource, it's because you are trying to set a foreign key. In that case, you should use [``](./ReferenceNodeInput.md) to fetch the choices instead (see next section). + +## Selecting a Foreign Key + +If you use `` to set a foreign key for a many-to-one or a one-to-one relationship, you’ll have to [fetch choices](#fetching-choices), as explained in the previous section. + +As this is a common task, react-admin provides a shortcut to do the same in a declarative way: [``](./ReferenceNodeInput.md): + +```tsx +import { Edit, SimpleForm, TextInput } from 'react-admin'; +import { ReferenceNodeInput, TreeInput } from '@react-admin/ra-tree'; + +const ProductEdit = () => ( + + + + + + + + +); +``` + diff --git a/docs/TreeWithDetails.md b/docs/TreeWithDetails.md index 3f31da98f10..bdeef0b6734 100644 --- a/docs/TreeWithDetails.md +++ b/docs/TreeWithDetails.md @@ -69,3 +69,40 @@ const App = () => ( ``` Check [the `ra-tree` documentation](https://marmelab.com/ra-enterprise/modules/ra-tree#treewithdetails-component) for more details. + +## Selecting a Node + +If you need to let users select a node in a tree, use the [``](./TreeInput.md) component. + +```tsx +import { Edit, SimpleForm, TextInput } from 'react-admin'; +import { TreeInput } from '@react-admin/ra-tree'; + +export const ProductEdit = () => ( + + + + + + + +); +``` + + \ No newline at end of file diff --git a/docs/img/ReferenceNodeInput-TreeInput-basic.mp4 b/docs/img/ReferenceNodeInput-TreeInput-basic.mp4 new file mode 100644 index 00000000000..c703fff1324 Binary files /dev/null and b/docs/img/ReferenceNodeInput-TreeInput-basic.mp4 differ diff --git a/docs/img/ReferenceNodeInput-TreeInput-basic.webm b/docs/img/ReferenceNodeInput-TreeInput-basic.webm new file mode 100644 index 00000000000..351e6754187 Binary files /dev/null and b/docs/img/ReferenceNodeInput-TreeInput-basic.webm differ diff --git a/docs/img/ReferenceNodeInput-TreeInput-multiple.mp4 b/docs/img/ReferenceNodeInput-TreeInput-multiple.mp4 new file mode 100644 index 00000000000..9c5f468b558 Binary files /dev/null and b/docs/img/ReferenceNodeInput-TreeInput-multiple.mp4 differ diff --git a/docs/img/ReferenceNodeInput-TreeInput-multiple.webm b/docs/img/ReferenceNodeInput-TreeInput-multiple.webm new file mode 100644 index 00000000000..59a0e025daf Binary files /dev/null and b/docs/img/ReferenceNodeInput-TreeInput-multiple.webm differ diff --git a/docs/navigation.html b/docs/navigation.html index ccf80f31acc..9d85923112c 100644 --- a/docs/navigation.html +++ b/docs/navigation.html @@ -190,6 +190,7 @@
  • <ReferenceArrayInput>
  • <ReferenceManyInput>
  • <ReferenceManyToManyInput>
  • +
  • <ReferenceNodeInput>
  • <ReferenceOneInput>
  • <RichTextInput>
  • <SelectInput>
  • @@ -198,6 +199,7 @@
  • <TextInput>
  • <TimeInput>
  • <TranslatableInputs>
  • +
  • <TreeInput>
  • useInput