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

@mantine/notifications Allow global notifications auto close customization #5329

Closed
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
15 changes: 15 additions & 0 deletions docs/pages/others/notifications.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,21 @@ function Demo() {
}
```

Or globally customize the duration based on the notification data

```tsx
import { Notifications, NotificationData, DEFAULT_AUTO_CLOSE_DURATION_MS } from '@mantine/notifications';

// All notifications will be closed automatically in 4000ms
function Demo() {
return <Notifications autoClose={(data: NotificationData) => {
if (data.color === 'red') return false;

return DEFAULT_AUTO_CLOSE_DURATION_MS;
}} />;
}
```

Or per notification in `notifications.show`/`notifications.update` functions:

```tsx
Expand Down
4 changes: 2 additions & 2 deletions src/mantine-notifications/src/NotificationContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import { getAutoClose } from './get-auto-close/get-auto-close';
interface NotificationContainerProps extends NotificationProps {
data: NotificationData;
onHide: (id: string) => void;
autoClose: number | false;
autoClose: number | false | ((data: NotificationData) => number | false);
}

export const NotificationContainer = forwardRef<HTMLDivElement, NotificationContainerProps>(
({ data, onHide, autoClose, ...others }, ref) => {
const { autoClose: _autoClose, message, ...notificationProps } = data;
const autoCloseDuration = getAutoClose(autoClose, data.autoClose);
const autoCloseDuration = getAutoClose(autoClose, data);
const autoCloseTimeout = useRef<number>();

const cancelAutoClose = () => window.clearTimeout(autoCloseTimeout.current);
Expand Down
9 changes: 6 additions & 3 deletions src/mantine-notifications/src/Notifications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
notificationsStore,
hideNotification,
notifications,
NotificationData,
} from './notifications.store';
import { NotificationContainer } from './NotificationContainer';
import { getNotificationStateStyles } from './get-notification-state-styles';
Expand Down Expand Up @@ -59,8 +60,8 @@ export interface NotificationsProps
| 'bottom-right'
| 'bottom-center';

/** Auto close timeout for all notifications in ms, `false` to disable auto close, can be overwritten for individual notifications in `notifications.show` function, `4000` by defualt */
autoClose?: number | false;
/** Auto close timeout for all notifications in ms, `false` to disable auto close, can be overwritten for individual notifications in `notifications.show` function, `4000` by defualt, or a function receiving the notification data to customize the auto close ruleset */
autoClose?: number | false | ((data: NotificationData) => number | false);

/** Notification transition duration in ms, `250` by default */
transitionDuration?: number;
Expand Down Expand Up @@ -102,9 +103,11 @@ export type NotificationsFactory = Factory<{
};
}>;

export const DEFAULT_AUTO_CLOSE_DURATION_MS = 4000;

const defaultProps: Partial<NotificationsProps> = {
position: 'bottom-right',
autoClose: 4000,
autoClose: DEFAULT_AUTO_CLOSE_DURATION_MS,
transitionDuration: 250,
containerWidth: 440,
notificationMaxHeight: 200,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
import { DEFAULT_AUTO_CLOSE_DURATION_MS } from '../Notifications';
import { NotificationData } from '../notifications.store';
import { getAutoClose } from './get-auto-close';

describe('@mantine/notifications/get-auto-close', () => {
const autoClose = (data: NotificationData) => {
if (data.color === 'red') return false;

return DEFAULT_AUTO_CLOSE_DURATION_MS;
};
const notificationData: NotificationData = {
message: (() => 'test')(),
};

it('prioritizes notification autoClose prop', () => {
expect(getAutoClose(false, 10)).toBe(10);
expect(getAutoClose(400, 10)).toBe(10);
expect(getAutoClose(400, false)).toBe(false);
expect(getAutoClose(false, { ...notificationData, autoClose: 10 })).toBe(10);
expect(getAutoClose(400, { ...notificationData, autoClose: 10 })).toBe(10);
expect(getAutoClose(400, { ...notificationData, autoClose: false })).toBe(false);
expect(getAutoClose(400, { ...notificationData, autoClose })).toBe(4000);
});

it('returns provider value if notification does not have autoClose prop', () => {
expect(getAutoClose(false, undefined!)).toBe(false);
expect(getAutoClose(400, undefined!)).toBe(400);
expect(getAutoClose(false, { ...notificationData, autoClose: undefined }!)).toBe(false);
expect(getAutoClose(400, { ...notificationData, autoClose: undefined }!)).toBe(400);
expect(getAutoClose(autoClose, { ...notificationData, autoClose: undefined }!)).toBe(4000);

const autoClose2 = (data: NotificationData) => {
if (data.color === 'red') return false;

return 5000;
};
expect(getAutoClose(autoClose, { ...notificationData, autoClose: autoClose2 })).toBe(
5000
);
});
});
16 changes: 10 additions & 6 deletions src/mantine-notifications/src/get-auto-close/get-auto-close.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { NotificationData } from '../notifications.store';

export function getAutoClose(
autoClose: boolean | number | undefined,
notificationAutoClose: boolean | number | undefined
autoClose: number | false | ((data: NotificationData) => number | false) | undefined,
notificationData: NotificationData
) {
if (typeof notificationAutoClose === 'number') {
return notificationAutoClose;
const _autoClose = notificationData.autoClose ?? autoClose;

if (typeof _autoClose === 'number') {
return _autoClose;
}

if (notificationAutoClose === false || autoClose === false) {
if (_autoClose === false) {
return false;
}

return autoClose;
return _autoClose?.(notificationData);
}
2 changes: 1 addition & 1 deletion src/mantine-notifications/src/notifications.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface NotificationData extends Omit<NotificationProps, 'onClose'> {
/** Determines whether notification should be closed automatically,
* number is auto close timeout in ms, overrides `autoClose` from `Notifications`
* */
autoClose?: boolean | number;
autoClose?: number | false | ((data: NotificationData) => number | false);

/** Called when notification closes */
onClose?: (props: NotificationData) => void;
Expand Down