import { AlertTriangle, CheckCircle2, Info, XCircle, type LucideIcon } from "lucide-react-native"; import { type ReactNode, useMemo } from "react"; import { Text, View } from "react-native"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; export type AlertVariant = "default" | "info" | "success" | "warning" | "error"; export interface AlertProps { title?: string; description?: ReactNode; variant?: AlertVariant; icon?: ReactNode; children?: ReactNode; testID?: string; } const VARIANT_ICON: Record, LucideIcon> = { info: Info, success: CheckCircle2, warning: AlertTriangle, error: XCircle, }; export function Alert({ title, description, variant = "default", icon, children, testID, }: AlertProps) { const { theme } = useUnistyles(); const accentColor = resolveAccentColor(variant, theme); const borderColor = variant === "success" ? theme.colors.border : accentColor; const containerStyle = useMemo( () => [styles.container, borderColor ? { borderColor } : null], [borderColor], ); const titleStyle = useMemo( () => [styles.title, accentColor ? { color: accentColor } : null], [accentColor], ); const resolvedIcon = useMemo(() => { if (icon !== undefined) return icon; if (variant === "default") return null; const Icon = VARIANT_ICON[variant]; return ; }, [icon, variant, theme, accentColor]); const hasDescription = description != null && description !== ""; return ( {resolvedIcon ? {resolvedIcon} : null} {title ? {title} : null} {hasDescription && typeof description === "string" ? ( {description} ) : null} {hasDescription && typeof description !== "string" ? ( {description} ) : null} {children ? {children} : null} ); } function resolveAccentColor( variant: AlertVariant, theme: ReturnType["theme"], ): string | null { if (variant === "info") return theme.colors.palette.blue[300]; if (variant === "success") return theme.colors.statusSuccess; if (variant === "warning") return theme.colors.palette.amber[500]; if (variant === "error") return theme.colors.destructive; return null; } const styles = StyleSheet.create((theme) => ({ container: { flexDirection: "row", alignItems: "flex-start", gap: theme.spacing[3], borderWidth: theme.borderWidth[1], borderColor: theme.colors.border, backgroundColor: "transparent", borderRadius: theme.borderRadius.xl, paddingVertical: theme.spacing[3], paddingHorizontal: theme.spacing[4], }, iconSlot: { paddingTop: 2, }, body: { flex: 1, minWidth: 0, gap: theme.spacing[1], }, title: { color: theme.colors.foreground, fontSize: theme.fontSize.base, fontWeight: theme.fontWeight.medium, }, description: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.sm, }, descriptionSlot: { flexShrink: 1, minWidth: 0, gap: theme.spacing[2], }, actions: { flexDirection: "row", gap: theme.spacing[2], marginTop: theme.spacing[2], }, }));