import { defineMessages, TLI18nMessage, useValue } from '@tldraw/editor' import { Toast as _Toast } from 'radix-ui' import { memo } from 'react' import { AlertSeverity, TLUiToast, useToasts } from '../context/toasts' import { useTranslation } from '../hooks/useTranslation/useTranslation' import { TLUiIconType } from '../icon-types' import { TldrawUiButton } from './primitives/Button/TldrawUiButton' import { TldrawUiButtonLabel } from './primitives/Button/TldrawUiButtonLabel' import { TldrawUiIcon } from './primitives/TldrawUiIcon' const messages = defineMessages({ toastClose: { id: 'toast.close', defaultMessage: 'Close' }, }) const DEFAULT_TOAST_DURATION = 4000 const SEVERITY_TO_ICON: { [msg in AlertSeverity]: TLUiIconType } = { success: 'check-circle', warning: 'warning-triangle', error: 'cross-circle', info: 'info-circle', } /** @internal */ // Keyed on the severity rather than written at the call site, which used to compose the id from // `severity` and so hid all four from the extractor. The `Record` keeps it complete: a new // severity won't compile until it has a label. const severityMessages: Record = defineMessages({ success: { id: 'toast.success', defaultMessage: 'Success' }, info: { id: 'toast.info', defaultMessage: 'Info' }, warning: { id: 'toast.warning', defaultMessage: 'Warning' }, error: { id: 'toast.error', defaultMessage: 'Error' }, }) function TldrawUiToast({ toast }: { toast: TLUiToast }) { const { removeToast } = useToasts() const msg = useTranslation() const onOpenChange = (isOpen: boolean) => { if (!isOpen) { removeToast(toast.id) } } const hasActions = toast.actions && toast.actions.length > 0 const icon = toast.icon || (toast.severity && SEVERITY_TO_ICON[toast.severity]) const iconLabel = toast.iconLabel || (toast.severity ? msg(severityMessages[toast.severity]) : '') return ( <_Toast.Root onOpenChange={onOpenChange} className="tlui-toast__container" duration={toast.keepOpen ? Infinity : DEFAULT_TOAST_DURATION} data-severity={toast.severity} > {icon && (
)}
{toast.title && <_Toast.Title className="tlui-toast__title">{toast.title}} {toast.description && ( <_Toast.Description className="tlui-toast__description"> {toast.description} )}
{toast.actions && (
{toast.actions.map((action, i) => ( <_Toast.Action key={i} altText={action.label} asChild onClick={action.onClick}> {action.label} ))} <_Toast.Close asChild> {toast.closeLabel ?? msg(messages.toastClose)}
)}
{!hasActions && ( <_Toast.Close asChild> {toast.closeLabel ?? msg(messages.toastClose)} )} ) } /** @public @react */ export const DefaultToasts = memo(function TldrawUiToasts() { const { toasts } = useToasts() const toastsArray = useValue('toasts', () => toasts.get(), []) return ( <> {toastsArray.map((toast) => ( ))} <_Toast.ToastViewport className="tlui-toast__viewport" /> ) })