import React, { useEffect } from 'react'; /** Tone hint used to colour the confirm button. */ export type ConfirmDialogTone = 'default' | 'destructive'; /** Props for {@link ConfirmDialog}. */ export interface ConfirmDialogProps { /** Controls visibility - mirror this in the caller's state. */ open: boolean; /** Called when the modal requests to close (Esc, backdrop, cancel). */ onOpenChange: (next: boolean) => void; /** Short headline rendered as the dialog title. */ title: string; /** Longer body copy explaining what will happen on confirm. */ description: string; /** Label of the affirmative button. Defaults to "Yes". */ confirmLabel?: string; /** Label of the dismissive button. Defaults to "No". */ cancelLabel?: string; /** Visual tone of the confirm button. Defaults to ``"default"``. */ tone?: ConfirmDialogTone; /** Disables both buttons while a parent-side request is in flight. */ busy?: boolean; /** Optional label shown on the confirm button while ``busy`` is true. */ busyLabel?: string; /** Fired when the user confirms; the parent runs the actual side effect. */ onConfirm: () => void; } /** * Generic Yes/No confirmation modal styled with the plugin's Tailwind * palette. Replaces ``window.confirm`` so destructive actions get a real, * themed dialog with Esc/backdrop handling. The caller owns the side effect * and the open/close state - this component is intentionally dumb. */ const ConfirmDialog = ({ open, onOpenChange, title, description, confirmLabel = 'Yes', cancelLabel = 'No', tone = 'default', busy = false, busyLabel, onConfirm, }: ConfirmDialogProps): JSX.Element | null => { useEffect(() => { if (!open) return undefined; const handleKey = (event: KeyboardEvent) => { if (event.key === 'Escape' && !busy) onOpenChange(false); }; window.addEventListener('keydown', handleKey); return () => window.removeEventListener('keydown', handleKey); }, [open, busy, onOpenChange]); if (!open) return null; const confirmClass = tone === 'destructive' ? 'bg-red-600 hover:bg-red-700 text-white' : 'bg-black hover:bg-gray-800 text-white'; return (
{description}