import { X } from "lucide-react-native"; import { useCallback, useMemo, type ReactNode } from "react"; import { Pressable, Text, View, type PressableStateCallbackType } from "react-native"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; export type SidebarCalloutActionVariant = "primary" | "secondary"; export interface SidebarCalloutAction { label: string; onPress: () => void; variant?: SidebarCalloutActionVariant; disabled?: boolean; testID?: string; } export type SidebarCalloutVariant = "default" | "success" | "error"; export interface SidebarCalloutProps { title?: string; description?: ReactNode; icon?: ReactNode; variant?: SidebarCalloutVariant; actions?: readonly SidebarCalloutAction[]; onDismiss?: () => void; testID?: string; } export function SidebarCalloutDescriptionText({ children }: { children: ReactNode }) { return {children}; } export function SidebarCallout({ title, description, icon, variant = "default", actions, onDismiss, testID, }: SidebarCalloutProps) { const { theme } = useUnistyles(); const visibleActions = (actions ?? []).slice(0, 2); const hasHeader = title != null || icon != null; const hasDescription = description != null && description !== ""; const containerStyle = useMemo( () => [styles.container, variant === "error" ? styles.containerError : null], [variant], ); return ( {hasHeader || onDismiss ? ( {hasHeader ? ( {icon ? {icon} : null} {title ? ( {title} ) : null} ) : null} {onDismiss ? ( {({ hovered }) => ( )} ) : null} ) : null} {hasDescription && typeof description === "string" ? ( {description} ) : null} {hasDescription && typeof description !== "string" ? ( {description} ) : null} {visibleActions.length > 0 ? ( {visibleActions.map((action, index) => ( ))} ) : null} ); } function SidebarCalloutActionButton({ action, testID, }: { action: SidebarCalloutAction; testID?: string; }) { const isPrimary = action.variant === "primary"; const labelStyle = useMemo( () => [styles.actionLabel, isPrimary ? styles.actionLabelPrimary : styles.actionLabelSecondary], [isPrimary], ); const pressableStyle = useCallback( ({ pressed }: PressableStateCallbackType) => [ styles.actionButton, isPrimary ? styles.actionButtonPrimary : styles.actionButtonSecondary, pressed ? styles.actionButtonPressed : null, action.disabled ? styles.actionButtonDisabled : null, ], [action.disabled, isPrimary], ); return ( {action.label} ); } const styles = StyleSheet.create((theme) => ({ container: { width: "100%", paddingVertical: theme.spacing[3], paddingHorizontal: theme.spacing[4], borderTopWidth: theme.borderWidth[1], borderTopColor: theme.colors.border, gap: theme.spacing[2], }, containerError: { borderTopColor: theme.colors.destructive, }, dismissButton: { width: 14, height: 14, alignItems: "center", justifyContent: "center", }, body: { gap: theme.spacing[2], }, topRow: { flexDirection: "row", alignItems: "flex-start", gap: theme.spacing[2], }, header: { flex: 1, flexDirection: "row", alignItems: "center", gap: theme.spacing[2], }, iconSlot: { alignItems: "center", justifyContent: "center", }, title: { flexShrink: 1, color: theme.colors.foreground, fontSize: theme.fontSize.sm, fontWeight: theme.fontWeight.normal, }, description: { color: theme.colors.foregroundMuted, fontSize: theme.fontSize.xs, }, descriptionSlot: { flexShrink: 1, minWidth: 0, gap: theme.spacing[2], }, actionRow: { flexDirection: "row", gap: theme.spacing[2], marginTop: theme.spacing[2], }, actionButton: { flex: 1, paddingVertical: theme.spacing[2], paddingHorizontal: theme.spacing[3], borderRadius: theme.borderRadius.md, borderWidth: theme.borderWidth[1], alignItems: "center", justifyContent: "center", }, actionButtonPrimary: { backgroundColor: theme.colors.foreground, borderColor: theme.colors.foreground, }, actionButtonSecondary: { backgroundColor: "transparent", borderColor: theme.colors.border, }, actionButtonPressed: { opacity: 0.8, }, actionButtonDisabled: { opacity: 0.5, }, actionLabel: { fontSize: theme.fontSize.xs, fontWeight: theme.fontWeight.medium, }, actionLabelPrimary: { color: theme.colors.surface0, }, actionLabelSecondary: { color: theme.colors.foreground, }, }));