Files
dashboards/components/ConfirmDialog.tsx
T

91 lines
2.2 KiB
TypeScript

"use client";
import { useEffect, useId, useRef } from "react";
import styles from "./ConfirmDialog.module.css";
export default function ConfirmDialog({
open,
title,
kicker = "Confirm",
message,
confirmLabel = "Confirm",
cancelLabel = "Cancel",
danger = false,
busy = false,
onConfirm,
onClose,
}: {
open: boolean;
title: string;
kicker?: string;
message: string;
confirmLabel?: string;
cancelLabel?: string;
danger?: boolean;
busy?: boolean;
onConfirm: () => void;
onClose: () => void;
}) {
const titleId = useId();
const cancelRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
if (!open) return;
const previousOverflow = document.body.style.overflow;
document.body.style.overflow = "hidden";
cancelRef.current?.focus();
const onKey = (event: KeyboardEvent) => {
if (event.key === "Escape" && !busy) onClose();
};
window.addEventListener("keydown", onKey);
return () => {
document.body.style.overflow = previousOverflow;
window.removeEventListener("keydown", onKey);
};
}, [open, busy, onClose]);
if (!open) return null;
return (
<div
className={styles.overlay}
role="presentation"
onMouseDown={(event) => {
if (event.target === event.currentTarget && !busy) onClose();
}}
>
<div
className={styles.dialog}
role="alertdialog"
aria-modal="true"
aria-labelledby={titleId}
>
<p className={styles.kicker}>{kicker}</p>
<h2 id={titleId} className={styles.title}>
{title}
</h2>
<p className={styles.message}>{message}</p>
<div className={styles.actions}>
<button
ref={cancelRef}
type="button"
className={`outline-btn ${styles.cancelBtn}`}
disabled={busy}
onClick={onClose}
>
{cancelLabel}
</button>
<button
type="button"
className={`outline-btn ${styles.confirmBtn} ${danger ? styles.confirmDanger : ""}`}
disabled={busy}
onClick={onConfirm}
>
{busy ? "…" : confirmLabel}
</button>
</div>
</div>
</div>
);
}