Skip to content
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
43 changes: 43 additions & 0 deletions react-responsive-modal/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -746,6 +746,49 @@ describe('modal', () => {
fireEvent.animationEnd(getByTestId('modal'));
expect(onAnimationEnd).toHaveBeenCalledTimes(1);
});

it('should pass the animation event to onAnimationEnd', async () => {
const onAnimationEnd = vitest.fn();
const { getByTestId } = render(
<Modal open onClose={() => null} onAnimationEnd={onAnimationEnd}>
<div>modal content</div>
</Modal>,
);

const modal = getByTestId('modal');
fireEvent.animationEnd(modal);
expect(onAnimationEnd).toHaveBeenCalledTimes(1);
expect(onAnimationEnd.mock.calls[0][0].target).toBe(modal);
});

it('should not be called when a child animation ends', async () => {
const onAnimationEnd = vitest.fn();
const { getByTestId } = render(
<Modal open onClose={() => null} onAnimationEnd={onAnimationEnd}>
<div data-testid="child">modal content</div>
</Modal>,
);

fireEvent.animationEnd(getByTestId('child'));
expect(onAnimationEnd).not.toHaveBeenCalled();
});

it('should not hide the modal when a child animation ends while closing', async () => {
const { getByTestId, queryByTestId, rerender } = render(
<Modal open onClose={() => null} animationDuration={0.01}>
<div data-testid="child">modal content</div>
</Modal>,
);

rerender(
<Modal open={false} onClose={() => null} animationDuration={0.01}>
<div data-testid="child">modal content</div>
</Modal>,
);

fireEvent.animationEnd(getByTestId('child'));
expect(queryByTestId('modal')).toBeTruthy();
});
});

describe('prop: containerId', () => {
Expand Down
13 changes: 10 additions & 3 deletions react-responsive-modal/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export interface ModalProps {
/**
* Callback fired when the Modal has exited and the animation is finished.
*/
onAnimationEnd?: () => void;
onAnimationEnd?: (event: React.AnimationEvent<HTMLDivElement>) => void;
children?: React.ReactNode;
}

Expand Down Expand Up @@ -313,12 +313,19 @@ export const Modal = React.forwardRef(
refShouldClose.current = false;
};

const handleAnimationEnd = () => {
const handleAnimationEnd = (
event: React.AnimationEvent<HTMLDivElement>,
) => {
// Ignore animations bubbling up from elements inside the modal
if (event.target !== event.currentTarget) {
return;
}

if (!open) {
setShowPortal(false);
}

onAnimationEnd?.();
onAnimationEnd?.(event);
};

const containerModal = container || refContainer.current;
Expand Down
2 changes: 1 addition & 1 deletion website/src/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ By default, the Modal will be rendered at the end of the html body tag. If you w
| **onClose\*** | `() => void` | | Callback fired when the Modal is requested to be closed by a click on the overlay or when user press esc key. |
| **onEscKeyDown\*** | `(event: KeyboardEvent) => void` | | Callback fired when the escape key is pressed. |
| **onOverlayClick\*** | `(event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void` | | Callback fired when the overlay is clicked. |
| **onAnimationEnd\*** | `() => void` | | Callback fired when the Modal has exited and the animation is finished. |
| **onAnimationEnd\*** | `(event: React.AnimationEvent<HTMLDivElement>) => void` | | Callback fired when the Modal has exited and the animation is finished. |

## License

Expand Down
Loading