import type { CSSProperties, ComponentType, ReactNode } from 'react'; /** Toast variants. `normal` is a Sonner alias for `default`. */ export type ToastType = 'default' | 'normal' | 'action' | 'info' | 'success' | 'warning' | 'error' | 'loading' | 'custom'; export type ToastPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center'; export type ToastLayout = 'stack' | 'normal'; export type RichColorsMode = 'soft' | 'solid' | 'minimal'; export type ToastSize = 'sm' | 'md' | 'lg'; export type ToastPriority = 'low' | 'normal' | 'high'; export type ToastStatus = 'idle' | 'loading' | 'success' | 'error'; export type SwipeDirection = 'left' | 'right' | 'up' | 'down'; export type Theme = 'light' | 'dark' | 'system'; /** Per-side spacing, mirroring Sonner's object form. */ export interface ToastOffset { top?: string | number; right?: string | number; bottom?: string | number; left?: string | number; } /** A node, or a function given the toast id so it can dismiss itself. */ export type ToastContent = ReactNode | ((id: string) => ReactNode); export type Direction = 'ltr' | 'rtl' | 'auto'; /** Per-part class name hooks, mirroring Sonner's `classNames`. */ export interface ToastClassNames { toast?: string; title?: string; description?: string; icon?: string; content?: string; actionButton?: string; cancelButton?: string; closeButton?: string; progressBar?: string; input?: string; default?: string; success?: string; error?: string; info?: string; warning?: string; loading?: string; } export interface ToastAction { label: ReactNode; /** * Accessible name, for when `label` is an icon rather than text. Without it * an icon-only button is announced as just "button". */ altText?: string; onClick: (event: React.MouseEvent) => void; /** Visual variant. */ style?: 'default' | 'primary' | 'secondary' | 'danger'; className?: string; /** Dismiss the toast after the click. Defaults to `true`. */ dismiss?: boolean; } export interface ToastCancel { label: ReactNode; /** Accessible name, for when `label` is an icon rather than text. */ altText?: string; onClick?: (event: React.MouseEvent) => void; className?: string; } export interface ToastInput { placeholder: string; onSubmit: (value: string) => void; /** Label for the submit button. Defaults to `Submit`. */ submitLabel?: string; submitClassName?: string; className?: string; defaultValue?: string; /** Allow submitting an empty value. Defaults to `false`. */ allowEmpty?: boolean; } /** Overridable icon set. */ export interface ToastIcons { success?: ReactNode; info?: ReactNode; warning?: ReactNode; error?: ReactNode; loading?: ReactNode; close?: ReactNode; } /** Options accepted by `toast()` and friends. */ export interface ToastOptions { /** Stable id. Passing an existing id updates that toast in place. */ id?: string | number; /** Primary message. Sonner alias for `content`. */ title?: ReactNode; content?: ReactNode; description?: ReactNode; /** Variant. Usually set for you by `toast.success()` and friends. */ type?: ToastType; /** ms before auto-dismiss. `0` or `Infinity` disables it. */ duration?: number; icon?: ReactNode; /** Single action button (Sonner-compatible). */ action?: ToastAction; /** Multiple action buttons (Vyrn extension). */ actions?: ToastAction[]; cancel?: ToastCancel; input?: ToastInput; position?: ToastPosition; className?: string; descriptionClassName?: string; classNames?: ToastClassNames; /** Inline styles (Sonner-compatible). */ style?: CSSProperties; /** Inline styles (legacy Vyrn alias for `style`). */ customStyles?: CSSProperties; actionButtonStyle?: CSSProperties; cancelButtonStyle?: CSSProperties; /** Strip all built-in styling. */ unstyled?: boolean; /** Invert the surface against the page theme. */ invert?: boolean; richColors?: boolean | RichColorsMode; /** Show the close button. */ closeButton?: boolean; /** Legacy alias for `closeButton`. */ showCloseButton?: boolean; showProgressBar?: boolean; /** Allow manual dismissal (close button / swipe / Escape). Defaults to `true`. */ dismissible?: boolean; /** Dismiss when the toast body is clicked. */ closeOnClick?: boolean; /** Suppress this toast if an identical message of the same type is showing. */ preventDuplicate?: boolean; /** Announce assertively regardless of type. */ important?: boolean; priority?: ToastPriority; size?: ToastSize; expandable?: boolean; expanded?: boolean; /** Determinate progress, 0-100. Suppresses the duration countdown bar. */ progress?: number; status?: ToastStatus; /** Group key — toasts sharing a key collapse into a single slot. */ groupId?: string; soundEffect?: string; onClick?: (event: React.MouseEvent) => void; /** Fired when the toast is dismissed by the user or programmatically. */ onDismiss?: (toast: ToastRecord) => void; /** Fired when the toast closes because its duration elapsed. */ onAutoClose?: (toast: ToastRecord) => void; /** Legacy: fired on any close, after onDismiss/onAutoClose. */ onClose?: () => void; /** Render the toast yourself. */ customComponent?: ComponentType<{ toast: ToastRecord; dismiss: () => void; }>; /** Fully custom content, bypassing the toast chrome. */ jsx?: ToastContent; } /** A toast as held by the store: options with everything resolved. */ export interface ToastRecord extends Omit { id: string; type: ToastType; content: ReactNode; duration: number; /** Monotonic creation order, used for stable sorting. */ seq: number; } /** Legacy v4 shape. Kept so existing `ToastProps` consumers still compile. */ export type ToastProps = ToastRecord; export interface ToasterProps { children?: ReactNode; position?: ToastPosition; /** Legacy alias for `position`. */ defaultPosition?: ToastPosition; layout?: ToastLayout; /** Legacy alias for `layout`. */ defaultLayout?: ToastLayout; /** Max simultaneously visible toasts. Extras queue. */ visibleToasts?: number; /** Legacy alias for `visibleToasts`. */ maxToasts?: number; duration?: number; /** Legacy alias for `duration`. */ defaultDuration?: number; theme?: Theme; dir?: Direction; richColors?: boolean | RichColorsMode; /** Keep all toasts expanded instead of collapsing them into a stack. */ expand?: boolean; closeButton?: boolean; /** Legacy alias for `closeButton`. */ showCloseButton?: boolean; showProgressBar?: boolean; /** Apply the semantic accent colour to toast surfaces. */ color?: boolean; invert?: boolean; size?: ToastSize; /** Gap between toasts, in px. */ gap?: number; /** Distance from the viewport edge. Number is px; object sets each side. */ offset?: string | number | ToastOffset; /** Same, below 600px wide. */ mobileOffset?: string | number | ToastOffset; /** * Defaults merged into every toast. `types` narrows them per variant, so * `{ types: { error: { duration: 8000 } } }` only affects error toasts. */ toastOptions?: ToastOptions & { types?: Partial>; }; className?: string; /** Legacy alias for `className` on the container. */ containerClassName?: string; style?: CSSProperties; /** Directions a toast can be swiped away in. Defaults to the sensible pair for `position`. */ swipeDirections?: SwipeDirection[]; /** Legacy: a single swipe direction. */ swipeDirection?: SwipeDirection; /** Fraction of the toast width/height a swipe must cover to dismiss. */ swipeThreshold?: number; /** Key combo that moves focus into the toast list. Defaults to `['altKey','KeyT']`. */ hotkey?: string[]; /** Pause timers while the document is hidden. */ pauseWhenPageIsHidden?: boolean; /** Pause timers while the window is not focused (another app or window). */ pauseOnFocusLoss?: boolean; /** * Put the newest toast nearest the viewport edge. `false` keeps the oldest * in front, so new toasts append behind it. */ newestFirst?: boolean; /** Dismiss a toast when its body is clicked. */ closeOnClick?: boolean; /** Accessible label for the toast region. */ containerAriaLabel?: string; /** Accessible label for the close button. Translate this for i18n. */ closeButtonAriaLabel?: string; icons?: ToastIcons; loadingIcon?: ReactNode; /** Base z-index for the toast region. */ zIndex?: number; } /** Legacy v4 name. */ export type ToastProviderProps = ToasterProps; export interface PromiseOptions { loading?: ReactNode; success?: ReactNode | ((data: T) => ReactNode); error?: ReactNode | ((error: unknown) => ReactNode); description?: ReactNode | ((dataOrError: unknown) => ReactNode); finally?: () => void | Promise; onSuccess?: (data: T) => void; onError?: (error: unknown) => void; /** Duration for the resolved (success) toast. */ duration?: number; /** Duration for the rejected (error) toast. */ errorDuration?: number; cancel?: ToastCancel; id?: string | number; position?: ToastPosition; } export interface PromiseResult { /** Id of the toast tracking the promise. */ id: string; /** Await the underlying promise, re-throwing any rejection. */ unwrap: () => Promise; } export interface ToastGroupOptions { groupId: string; groupTitle?: string; } export interface ToastTheme { background: string; text: string; border: string; progressBar: string; }