Files
UTMS-NG-FE/components/ui/Dialog.tsx
2026-04-21 06:30:48 +07:00

61 lines
1.6 KiB
TypeScript

import { ReactNode, useEffect } from "react";
import { createPortal } from "react-dom";
type DialogProps = {
open: boolean;
title: string;
description?: string;
children: ReactNode;
onClose: () => void;
footer?: ReactNode;
size?: "sm" | "lg" | "xl";
loading?: boolean;
};
const sizeClass = {
sm: "modal-dialog modal-sm",
lg: "modal-dialog modal-lg",
xl: "modal-dialog modal-xl"
};
export default function Dialog({
open,
title,
description,
children,
onClose,
footer,
size = "sm",
loading
}: DialogProps) {
useEffect(() => {
if (!open) return;
const onEsc = (event: KeyboardEvent) => {
if (event.key === "Escape") onClose();
};
window.addEventListener("keydown", onEsc);
return () => window.removeEventListener("keydown", onEsc);
}, [open, onClose]);
if (!open) return null;
return createPortal(
<div className="modal d-block" style={{ background: "rgba(0,0,0,.4)" }}>
<div className={sizeClass[size]} style={{ marginTop: "6rem" }}>
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title">{title}</h5>
<button className="btn-close" onClick={onClose} aria-label="close" />
</div>
<div className="modal-body">
{description && <p className="text-muted mb-3">{description}</p>}
{loading ? <div className="text-center text-muted">Loading...</div> : children}
</div>
{footer && <div className="modal-footer">{footer}</div>}
</div>
</div>
</div>,
document.body
);
}