1"use client";2import { useEffect, useRef, type ReactNode } from "react";3import clsx from "clsx";45interface Props {6 open: boolean;7 title: string;8 children?: ReactNode;9 confirmLabel?: string;10 danger?: boolean;11 busy?: boolean;12 onConfirm: () => void;13 onCancel: () => void;14}1516export function ConfirmDialog({ open, title, children, confirmLabel = "Confirm", danger, busy, onConfirm, onCancel }: Props) {17 const ref = useRef<HTMLDialogElement>(null);18 useEffect(() => {19 const d = ref.current;20 if (!d) return;21 if (open && !d.open) d.showModal();22 if (!open && d.open) d.close();23 }, [open]);24 return (25 <dialog ref={ref} onClose={onCancel} onCancel={onCancel} className="m-auto w-[min(92vw,28rem)] rounded-lg border border-border bg-surface-1 p-0 text-ink-1 shadow-xl">26 <div className="p-4">27 <h2 className="text-base font-semibold">{title}</h2>28 {children && <div className="mt-2 text-sm text-ink-2">{children}</div>}29 </div>30 <div className="flex justify-end gap-2 border-t border-hairline px-4 py-3">31 <button className="btn" onClick={onCancel} disabled={busy}>32 Cancel33 </button>34 <button className={clsx("btn", danger ? "btn-danger" : "btn-primary")} onClick={onConfirm} disabled={busy}>35 {busy ? "Working…" : confirmLabel}36 </button>37 </div>38 </dialog>39 );40}4142export function Modal({ open, title, children, onClose, wide }: { open: boolean; title: string; children: ReactNode; onClose: () => void; wide?: boolean }) {43 const ref = useRef<HTMLDialogElement>(null);44 useEffect(() => {45 const d = ref.current;46 if (!d) return;47 if (open && !d.open) d.showModal();48 if (!open && d.open) d.close();49 }, [open]);50 return (51 <dialog ref={ref} onClose={onClose} onCancel={onClose} className={clsx("m-auto rounded-lg border border-border bg-surface-1 p-0 text-ink-1 shadow-xl", wide ? "w-[min(96vw,56rem)]" : "w-[min(92vw,32rem)]")}>52 <div className="flex items-center justify-between border-b border-hairline px-4 py-3">53 <h2 className="text-base font-semibold">{title}</h2>54 <button className="btn btn-ghost btn-sm" onClick={onClose} aria-label="Close">55 ✕56 </button>57 </div>58 <div className="max-h-[80dvh] overflow-y-auto p-4">{children}</div>59 </dialog>60 );61}62