@flanksource/clicky-ui
Version:
Flanksource Clicky UI — React component library built on shadcn/ui with light/dark and density theming.
92 lines (91 loc) • 2.97 kB
JavaScript
import { jsx, jsxs } from "react/jsx-runtime";
import { useRef, useEffect } from "react";
import { cn } from "../lib/utils.js";
import { Icon } from "../data/Icon.js";
const sizeClass = {
sm: "max-w-sm max-h-[90vh]",
md: "max-w-md max-h-[90vh]",
lg: "max-w-2xl max-h-[90vh]",
xl: "max-w-4xl max-h-[90vh]",
full: "max-w-[95vw] max-h-[95vh]"
};
function Modal({
open,
onClose,
title,
size = "md",
closeOnBackdrop = true,
closeOnEsc = true,
hideClose = false,
className,
headerSlot,
footer,
children
}) {
const dialogRef = useRef(null);
useEffect(() => {
if (!open || !closeOnEsc) return;
const onKey = (e) => {
if (e.key === "Escape") onClose();
};
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [open, closeOnEsc, onClose]);
useEffect(() => {
var _a;
if (!open) return;
const prev = document.activeElement;
(_a = dialogRef.current) == null ? void 0 : _a.focus();
return () => {
var _a2;
return (_a2 = prev == null ? void 0 : prev.focus) == null ? void 0 : _a2.call(prev);
};
}, [open]);
if (!open) return null;
return /* @__PURE__ */ jsx(
"div",
{
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40",
onClick: closeOnBackdrop ? onClose : void 0,
role: "presentation",
children: /* @__PURE__ */ jsxs(
"div",
{
ref: dialogRef,
tabIndex: -1,
role: "dialog",
"aria-modal": "true",
"aria-label": typeof title === "string" ? title : void 0,
className: cn(
"relative bg-background border border-border rounded-lg shadow-xl w-full flex flex-col",
sizeClass[size],
className
),
onClick: (e) => e.stopPropagation(),
children: [
(title || headerSlot || !hideClose) && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-density-2 px-density-4 py-density-3 border-b border-border", children: [
title && /* @__PURE__ */ jsx("h2", { className: "text-sm font-semibold flex-1", children: title }),
headerSlot,
!hideClose && /* @__PURE__ */ jsx(
"button",
{
type: "button",
onClick: onClose,
"aria-label": "Close",
className: "text-muted-foreground hover:text-foreground",
children: /* @__PURE__ */ jsx(Icon, { name: "codicon:close" })
}
)
] }),
/* @__PURE__ */ jsx("div", { className: "flex-1 overflow-auto px-density-4 py-density-3", children }),
footer && /* @__PURE__ */ jsx("div", { className: "px-density-4 py-density-3 border-t border-border", children: footer })
]
}
)
}
);
}
export {
Modal
};
//# sourceMappingURL=Modal.js.map