-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathnotificationToast.tsx
More file actions
59 lines (55 loc) · 2.79 KB
/
Copy pathnotificationToast.tsx
File metadata and controls
59 lines (55 loc) · 2.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* The console's `toast` surface.
*
* `NotificationProvider` presents four of the five spec display types through
* surface components (#3014); `toast` is the one it delegates, and in the
* console that delegate is sonner. This module is that bridge — it is the
* ONLY place a notification becomes a sonner call, so the mapping (severity →
* variant, `duration: 0` → persistent, first action → the toast's action
* button) lives in one testable function rather than inline in the shell.
*
* Non-toast display types never reach here: the provider routes them to
* `NotificationBanners` / `NotificationSnackbar` / `NotificationAlerts` /
* `NotificationInline` instead.
*/
import { toast } from 'sonner';
import type { NotificationItem, NotificationSeverityLevel } from '@object-ui/react';
import { isLucideIconName, LazyIcon } from '@object-ui/components';
/**
* Typed as `Record<NotificationSeverityLevel, …>` so a new severity in the spec
* `NotificationSeveritySchema` fails type-check here until it has a variant,
* rather than silently rendering as a neutral toast.
*/
const TOAST_BY_SEVERITY: Record<NotificationSeverityLevel, (message: string, data?: unknown) => unknown> = {
info: (message, data) => toast.info(message, data as never),
success: (message, data) => toast.success(message, data as never),
warning: (message, data) => toast.warning(message, data as never),
error: (message, data) => toast.error(message, data as never),
};
/**
* Present one `displayType: 'toast'` notification through sonner.
*
* Duration follows the notification contract: `0` means persistent (sonner's
* `Infinity`), and an absent duration defers to the `ConsoleToaster` default
* rather than being invented here.
*/
export function presentNotificationToast(notification: NotificationItem): void {
const show = TOAST_BY_SEVERITY[notification.severity] ?? TOAST_BY_SEVERITY.info;
// A toast carries at most one action button — sonner has one `action` slot,
// and a notification needing more than one belongs on a banner or an alert.
const action = notification.actions?.[0];
// The spec `icon` override, matching what the four surface components do.
// Only a REAL Lucide name is passed: `LazyIcon` degrades an unknown one to a
// `Database` glyph, whereas omitting the key leaves ConsoleToaster's severity
// icon in place — the better fallback for a typo.
const icon = isLucideIconName(notification.icon)
? <LazyIcon name={notification.icon} className="h-4 w-4" />
: undefined;
show(notification.title, {
description: notification.message,
duration: notification.duration === 0 ? Infinity : notification.duration,
dismissible: notification.dismissible,
...(icon ? { icon } : {}),
...(action ? { action: { label: action.label, onClick: action.onClick } } : {}),
});
}