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

feat(Toaster): added onClose callback #1902

Merged
merged 1 commit into from
Oct 19, 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
1 change: 1 addition & 0 deletions src/components/Toaster/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ Accepts the argument `toastOptions` with ongoing notification details:
| isClosable | `boolean` | | `true` | A configuration that manages the visibility of the X icon, which allows the user to close the notification |
| actions | `ToastAction[]` | | `undefined` | An array of [actions](./types.ts#L9) that display after `content` |
| renderIcon | `(toastProps: ToastProps) => ReactNode` | | `undefined` | Used to customize the toast icon. Type-based behavior is used by default |
| onClose | `() => void` | | `undefined` | Callback which calls when close button is clicked |

Every `action` is an object with following parameters:

Expand Down
15 changes: 11 additions & 4 deletions src/components/Toaster/Toast/Toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,12 +94,19 @@ export const Toast = React.forwardRef<HTMLDivElement, ToastUnitedProps>(function
autoHiding: timeoutProp = DEFAULT_TIMEOUT,
isClosable = true,
mobile = false,
onClose,
removeCallback,
} = props;

const onClose = React.useCallback(() => removeCallback(name), [removeCallback, name]);
const handleClose = React.useCallback(() => {
removeCallback(name);

if (onClose) {
onClose();
}
}, [removeCallback, onClose, name]);
const timeout = typeof timeoutProp === 'number' ? timeoutProp : undefined;
const closeOnTimeoutProps = useCloseOnTimeout<HTMLDivElement>({onClose, timeout});
const closeOnTimeoutProps = useCloseOnTimeout<HTMLDivElement>({onClose: handleClose, timeout});

const mods = {
mobile,
Expand All @@ -120,7 +127,7 @@ export const Toast = React.forwardRef<HTMLDivElement, ToastUnitedProps>(function
size="s"
view="flat"
className={b('btn-close')}
onClick={onClose}
onClick={handleClose}
extraProps={{'aria-label': i18n('label_close-button')}}
>
<Icon data={Xmark} />
Expand All @@ -129,7 +136,7 @@ export const Toast = React.forwardRef<HTMLDivElement, ToastUnitedProps>(function
{hasContent && (
<div className={b('content', {'without-title': !hasTitle})}>{content}</div>
)}
{renderActions({actions, onClose})}
{renderActions({actions, onClose: handleClose})}
</div>
</div>
);
Expand Down
19 changes: 19 additions & 0 deletions src/components/Toaster/__tests__/ToasterProvider.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,4 +409,23 @@ describe('modal remains open after toaster close', () => {
expect(toast).not.toBeInTheDocument();
expect(modal).toBeInTheDocument();
});

it('Toaster calls onClose callback when close icon is clicked', async () => {
const {providerAPI} = setup();

const mockOnCloseFn = jest.fn();

act(() => {
providerAPI.add({...toastProps, isClosable: true, onClose: mockOnCloseFn});
});

const toast = getToast();

const closeToastButton = await within(toast).findByRole('button');

fireEvent.click(closeToastButton);
tick(toast, 0);

expect(mockOnCloseFn).toHaveBeenCalled();
});
});
2 changes: 2 additions & 0 deletions src/components/Toaster/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export type ToastProps = {
isClosable?: boolean;
actions?: ToastAction[];

onClose?: () => void;

/** Function. Use for toast icon customization. By default type-based behavior is used */
renderIcon?: (toastProps: ToastProps) => React.ReactNode;
};
Expand Down
Loading