import { useCallback, useEffect, useState } from "react"; import { Modal, Pressable, View } from "react-native"; import { useThemeColor } from "../lib/useThemeColor"; import { cn } from "../lib/cn"; import { AppText } from "./AppText"; export type ConfirmDialogRequest = { readonly title: string; readonly message?: string; readonly cancelText?: string; readonly confirmText: string; readonly destructive?: boolean; readonly onConfirm: () => void; readonly onCancel?: () => void; }; let presentRequest: ((request: ConfirmDialogRequest) => void) | null = null; /** * Imperative confirm dialog, Alert.alert-shaped. Native iOS alerts already * match the app (and support per-button destructive red), so this is for * Android, where the native dialog can only theme all confirm buttons at * once. Requires ConfirmDialogHost to be mounted at the app root. */ export function showConfirmDialog(request: ConfirmDialogRequest): void { presentRequest?.(request); } /** * Android-style alert dialog matching the native one themed by * withAndroidModernAlertDialog — left-aligned text, right-aligned text * buttons — with what the native theme can't do: a per-dialog destructive * button color and a dimmer message than the title. */ export function ConfirmDialogHost() { const [request, setRequest] = useState(null); const pressedOverlay = useThemeColor("--color-subtle"); useEffect(() => { presentRequest = setRequest; return () => { presentRequest = null; }; }, []); const handleCancel = useCallback(() => { request?.onCancel?.(); setRequest(null); }, [request]); const handleConfirm = useCallback(() => { request?.onConfirm(); setRequest(null); }, [request]); return ( {request === null ? null : ( {request.title} {request.message === undefined ? null : ( {request.message} )} {request.cancelText ?? "Cancel"} {request.confirmText} )} ); }