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

Avoid Cloning Buttons In SimpleFormIterator #9805

Merged
merged 4 commits into from
May 2, 2024
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
31 changes: 31 additions & 0 deletions docs/Upgrade.md
Original file line number Diff line number Diff line change
Expand Up @@ -928,6 +928,37 @@ If you were using this prop, you can safely remove it.

The `data-generator-retail` package has been updated to provide types for all its records. In the process, we renamed the `commands` resource to `orders`. Accordingly, the `nb_commands` property of the `customers` resource has been renamed to `nb_orders` and the `command_id` property of the `invoices` and `reviews` resources has been renamed to `order_id`.

## `<SimpleFormIterator>` No Longer Clones Its Buttons

`<SimpleFormIterator>` used to clones the add, remove and reorder buttons and inject some props to them such as `onClick` and `className`.
If you relied on those props in your custom buttons, you should now leverage the following hooks:

- `useSimpleFormIterator` for buttons that are not tied to an item such as the add button.

```diff
- import { Button, ButtonProps } from 'react-admin';
+ import { Button, ButtonProps, useSimpleFormIterator } from 'react-admin';

export const MyAddButton = (props: ButtonProps) => {
+ const { add } = useSimpleFormIterator();
- return <Button {...props}>Add</Button>;
+ return <Button {...props} onClick={() => add()}>Add</Button>;
}
```

- `useSimpleFormIteratorItem` for buttons that are tied to an item such as the remove and reorder buttons.

```diff
- import { Button, ButtonProps } from 'react-admin';
+ import { Button, ButtonProps, useSimpleFormIteratorItem } from 'react-admin';

export const MyRemoveButton = (props: ButtonProps) => {
+ const { remove } = useSimpleFormIteratorItem();
- return <Button {...props}>Add</Button>;
+ return <Button {...props} onClick={() => remove()}>Add</Button>;
}
```

## Upgrading to v4

If you are on react-admin v3, follow the [Upgrading to v4](https://marmelab.com/react-admin/doc/4.16/Upgrade.html) guide before upgrading to v5.
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import * as React from 'react';
import AddIcon from '@mui/icons-material/AddCircleOutline';
import clsx from 'clsx';
import { useSimpleFormIterator } from './useSimpleFormIterator';

import { IconButtonWithTooltip, ButtonProps } from '../../button';

export const AddItemButton = (props: ButtonProps) => {
const { add } = useSimpleFormIterator();
const { add, source } = useSimpleFormIterator();
const { className, ...rest } = props;
return (
<IconButtonWithTooltip
label="ra.action.add"
size="small"
onClick={() => add()}
color="primary"
{...props}
className={clsx(`button-add button-add-${source}`, className)}
{...rest}
>
<AddIcon fontSize="small" />
</IconButtonWithTooltip>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
import * as React from 'react';

import clsx from 'clsx';
import { IconButtonWithTooltip } from '../../button';
import ArrowUpwardIcon from '@mui/icons-material/ArrowCircleUp';
import ArrowDownwardIcon from '@mui/icons-material/ArrowCircleDown';
import { useSimpleFormIteratorItem } from './useSimpleFormIteratorItem';
import { useSimpleFormIterator } from './useSimpleFormIterator';

export const ReOrderButtons = ({ className }: { className?: string }) => {
const { index, total, reOrder } = useSimpleFormIteratorItem();
const { source } = useSimpleFormIterator();

return (
<span className={className}>
<span
className={clsx(
`button-reorder button-reorder-${source}-${index}`,
className
)}
>
<IconButtonWithTooltip
label="ra.action.move_up"
size="small"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
import * as React from 'react';
import CloseIcon from '@mui/icons-material/RemoveCircleOutline';
import clsx from 'clsx';

import { IconButtonWithTooltip, ButtonProps } from '../../button';
import { useSimpleFormIteratorItem } from './useSimpleFormIteratorItem';
import { useSimpleFormIterator } from './useSimpleFormIterator';

export const RemoveItemButton = (props: Omit<ButtonProps, 'onClick'>) => {
const { remove } = useSimpleFormIteratorItem();
const { remove, index } = useSimpleFormIteratorItem();
const { source } = useSimpleFormIterator();
const { className, ...rest } = props;

return (
<IconButtonWithTooltip
label="ra.action.remove"
size="small"
onClick={() => remove()}
color="warning"
{...props}
className={clsx(
`button-remove button-remove-${source}-${index}`,
className
)}
{...rest}
>
<CloseIcon fontSize="small" />
</IconButtonWithTooltip>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import * as React from 'react';
import {
Children,
cloneElement,
MouseEvent,
MouseEventHandler,
ReactElement,
ReactNode,
useCallback,
Expand Down Expand Up @@ -125,16 +122,6 @@ export const SimpleFormIterator = (inProps: SimpleFormIteratorProps) => {
[append, children, resetField, source, fields.length]
);

// add field and call the onClick event of the button passed as addButton prop
const handleAddButtonClick = (
originalOnClickHandler: MouseEventHandler
) => (event: MouseEvent) => {
addField();
if (originalOnClickHandler) {
originalOnClickHandler(event);
}
};

const handleReorder = useCallback(
(origin: number, destination: number) => {
move(origin, destination);
Expand Down Expand Up @@ -197,15 +184,7 @@ export const SimpleFormIterator = (inProps: SimpleFormIteratorProps) => {
<div className={SimpleFormIteratorClasses.buttons}>
{!disableAdd && (
<div className={SimpleFormIteratorClasses.add}>
{cloneElement(addButton, {
className: clsx(
'button-add',
`button-add-${source}`
),
onClick: handleAddButtonClick(
addButton.props.onClick
),
})}
{addButton}
</div>
)}
{fields.length > 0 && !disableClear && !disableRemove && (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
import * as React from 'react';
import {
cloneElement,
MouseEvent,
MouseEventHandler,
ReactElement,
ReactNode,
useMemo,
} from 'react';
import { ReactElement, ReactNode, useMemo } from 'react';
import { Typography, Stack } from '@mui/material';
import clsx from 'clsx';
import {
Expand Down Expand Up @@ -41,7 +34,6 @@ export const SimpleFormIteratorItem = React.forwardRef(
record,
removeButton = <DefaultRemoveItemButton />,
reOrderButtons = <DefaultReOrderButtons />,
source,
} = props;
const resource = useResourceContext(props);
if (!resource) {
Expand All @@ -61,17 +53,6 @@ export const SimpleFormIteratorItem = React.forwardRef(
return disableRemove && disableRemove(record);
};

// remove field and call the onClick event of the button passed as removeButton prop
const handleRemoveButtonClick = (
originalOnClickHandler: MouseEventHandler,
index: number
) => (event: MouseEvent) => {
remove(index);
if (originalOnClickHandler) {
originalOnClickHandler(event);
}
};

const context = useMemo<SimpleFormIteratorItemContextValue>(
() => ({
index,
Expand Down Expand Up @@ -138,28 +119,9 @@ export const SimpleFormIteratorItem = React.forwardRef(
</SourceContextProvider>
{!disabled && (
<span className={SimpleFormIteratorClasses.action}>
{!disableReordering &&
cloneElement(reOrderButtons, {
index,
max: total,
reOrder,
className: clsx(
'button-reorder',
`button-reorder-${source}-${index}`
),
})}
{!disableReordering && reOrderButtons}

{!disableRemoveField(record) &&
cloneElement(removeButton, {
onClick: handleRemoveButtonClick(
removeButton.props.onClick,
index
),
className: clsx(
'button-remove',
`button-remove-${source}-${index}`
),
})}
{!disableRemoveField(record) && removeButton}
</span>
)}
</li>
Expand Down
Loading