sonner-native
Version:
An opinionated toast component for React Native. A port of @emilkowalski's sonner.
252 lines (230 loc) • 6.65 kB
text/typescript
import type React from 'react';
import type { TextStyle, ViewProps, ViewStyle } from 'react-native';
import type {
BaseAnimationBuilder,
EntryExitAnimationFunction,
ReanimatedKeyframe as Keyframe,
} from 'react-native-reanimated';
export type ToastStyles = {
toastContainer?: ViewStyle;
toast?: ViewStyle;
toastContent?: ViewStyle;
textContainer?: ViewStyle;
title?: TextStyle;
description?: TextStyle;
buttons?: ViewStyle;
closeButton?: ViewStyle;
closeButtonIcon?: ViewStyle;
};
type StyleProps = {
unstyled?: boolean;
style?: ViewStyle;
styles?: ToastStyles;
backgroundComponent?: React.ReactNode;
};
type PromiseOptions<T = unknown> = {
promise: Promise<T>;
success: (result: T) => string;
error: ((error: unknown) => string) | string;
loading: string;
styles?: {
loading?: ToastStyles;
success?: ToastStyles;
error?: ToastStyles;
};
};
export type ToastPosition = 'top-center' | 'bottom-center' | 'center';
export type ToastTheme = 'light' | 'dark' | 'system';
export type ToastSwipeDirection = 'left' | 'up';
export type ToastVariant = 'success' | 'error' | 'warning' | 'info' | 'loading';
export type ToastEntryExitAnimation =
| EntryExitAnimationFunction
| BaseAnimationBuilder
| typeof BaseAnimationBuilder
| Keyframe
| 'default';
export type ToastAnimation = {
enter?: ToastEntryExitAnimation;
exit?: ToastEntryExitAnimation;
};
export type AutoWiggle = 'never' | 'toast-change' | 'always';
export type ToastAction = {
label: string;
onClick: () => void;
};
export type ToastProps = StyleProps & {
id: string | number;
index: number;
title: string;
variant: ToastVariant;
numberOfToasts: number;
orderedToastIds: Array<string | number>;
jsx?: React.ReactNode;
description?: string;
invert?: boolean;
important?: boolean;
duration?: number;
position?: ToastPosition;
animation?: ToastAnimation;
dismissible?: boolean;
icon?: React.ReactNode;
action?: ToastAction | React.ReactNode;
cancel?: ToastAction | React.ReactNode;
close?: React.ReactNode;
closeButton?: boolean;
richColors?: boolean;
onDismiss?: (id: string | number) => void;
onAutoClose?: (id: string | number) => void;
promiseOptions?: PromiseOptions<unknown>;
actionButtonStyle?: ViewStyle;
actionButtonTextStyle?: TextStyle;
cancelButtonStyle?: ViewStyle;
cancelButtonTextStyle?: TextStyle;
onPress?: () => void;
allowFontScaling?: boolean;
maxFontSizeMultiplier?: number;
};
export type ToastRef = {
wiggle: () => void;
};
export function isToastAction(
action: ToastAction | React.ReactNode
): action is ToastAction {
return (
(action as ToastAction)?.onClick !== undefined &&
(action as ToastAction)?.label !== undefined
);
}
type ExternalToast = Omit<
ToastProps,
| 'id'
| 'type'
| 'title'
| 'jsx'
| 'promise'
| 'variant'
| 'index'
| 'numberOfToasts'
| 'orderedToastIds'
> & {
id?: string | number;
};
export type ToasterProps = Omit<StyleProps, 'style'> & {
duration?: number;
theme?: ToastTheme;
// richColors?: boolean; (false)
// expand?: boolean; // hover not supported on mobile
visibleToasts?: number;
position?: ToastPosition;
closeButton?: boolean;
offset?: number;
autoWiggleOnUpdate?: AutoWiggle;
style?: ViewStyle;
positionerStyle?: ViewStyle;
// dir?: 'ltr' | 'rtl'; (ltr)
// hotkey?: string; // hotkeys not supported on mobile
invert?: boolean;
allowFontScaling?: boolean;
maxFontSizeMultiplier?: number;
toastOptions?: {
actionButtonStyle?: ViewStyle;
actionButtonTextStyle?: TextStyle;
cancelButtonStyle?: ViewStyle;
cancelButtonTextStyle?: TextStyle;
titleStyle?: TextStyle;
descriptionStyle?: TextStyle;
style?: ViewStyle;
unstyled?: boolean;
toastContainerStyle?: ViewStyle;
toastContentStyle?: ViewStyle;
buttonsStyle?: ViewStyle;
closeButtonStyle?: ViewStyle;
closeButtonIconStyle?: ViewStyle;
textContainerStyle?: ViewStyle;
backgroundComponent?: React.ReactNode;
success?: ViewStyle;
error?: ViewStyle;
warning?: ViewStyle;
info?: ViewStyle;
loading?: ViewStyle;
};
gap?: number;
loadingIcon?: React.ReactNode;
richColors?: boolean;
// pauseWhenPageIsHidden?: boolean; (false)
icons?: {
success?: React.ReactNode;
error?: React.ReactNode;
warning?: React.ReactNode;
info?: React.ReactNode;
loading?: React.ReactNode;
};
swipeToDismissDirection?: ToastSwipeDirection;
pauseWhenPageIsHidden?: boolean;
enableStacking?: boolean;
animation?: ToastAnimation;
ToasterOverlayWrapper?: React.ComponentType<{ children: React.ReactNode }>;
ToastWrapper?: React.ComponentType<
ViewProps & {
children: React.ReactNode;
toastId: string | number;
}
>;
};
export type AddToastContextHandler = (
data: Omit<ToastProps, 'id' | 'index' | 'numberOfToasts' | 'orderedToastIds'> & { id?: string | number }
) => string | number;
export type StableToastContextType = Required<
Pick<
ToasterProps,
| 'duration'
| 'swipeToDismissDirection'
| 'closeButton'
| 'position'
| 'invert'
| 'icons'
| 'offset'
| 'pauseWhenPageIsHidden'
| 'gap'
| 'theme'
| 'toastOptions'
| 'autoWiggleOnUpdate'
| 'richColors'
| 'unstyled'
| 'enableStacking'
| 'visibleToasts'
| 'allowFontScaling'
>
> & {
addToast: AddToastContextHandler;
animation: ToastAnimation;
maxFontSizeMultiplier?: number;
};
export type DynamicToastContextType = {
toastHeights: Record<string | number, number>;
toastHeightsVersion: number;
isExpanded: boolean;
expand: () => void;
collapse: () => void;
toggleExpand: () => void;
};
/** @deprecated Use StableToastContextType & DynamicToastContextType */
export type ToasterContextType = StableToastContextType &
DynamicToastContextType;
export declare const toast: ((
message: string,
data?: ExternalToast
) => string | number) & {
success: (message: string, data?: ExternalToast) => string | number;
info: (message: string, data?: ExternalToast) => string | number;
error: (message: string, data?: ExternalToast) => string | number;
warning: (message: string, data?: ExternalToast) => string | number;
custom: (jsx: React.ReactElement, data?: ExternalToast) => string | number;
promise: <T>(
promise: Promise<T>,
options: Omit<PromiseOptions<T>, 'promise'> & ExternalToast
) => string | number;
loading: (message: string, data?: ExternalToast) => string | number;
dismiss: (id?: string | number) => string | number | undefined;
wiggle: (id: string | number) => void;
};