@divetocode/modal
Version:
A lightweight modal dialog system for React/Next.js
288 lines (283 loc) • 8.58 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var index_exports = {};
__export(index_exports, {
AlertModal: () => AlertModal,
ConfirmModal: () => ConfirmModal
});
module.exports = __toCommonJS(index_exports);
// src/AlertModal.tsx
var import_react = require("react");
// src/_Conponents/ConfirmButton.tsx
var import_jsx_runtime = require("react/jsx-runtime");
function ConfirmButton({
children,
className = "",
...props
}) {
const baseStyles = "w-full bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md transition cursor-pointer disabled:opacity-50 disabled:cursor-not-allowed";
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
"button",
{
...props,
className: `${baseStyles} ${className}`,
children
}
);
}
// src/AlertModal.tsx
var import_jsx_runtime2 = require("react/jsx-runtime");
function AlertModal({
isOpen,
message,
onClose,
confirmText,
alarmText
}) {
const [show, setShow] = (0, import_react.useState)(false);
(0, import_react.useEffect)(() => {
let timer;
if (isOpen) {
setShow(true);
} else {
timer = setTimeout(() => setShow(false), 300);
}
return () => timer && clearTimeout(timer);
}, [isOpen]);
if (!isOpen && !show) return null;
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"div",
{
style: {
position: "fixed",
inset: 0,
background: "rgba(0,0,0,0.4)",
backdropFilter: "blur(4px)",
display: "flex",
alignItems: "center",
justifyContent: "center",
zIndex: 50,
opacity: isOpen ? 1 : 0,
transition: "opacity 300ms ease"
},
onClick: onClose,
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
"div",
{
onClick: (e) => e.stopPropagation(),
style: {
background: "#fff",
borderRadius: "12px",
boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
width: "100%",
maxWidth: "28rem",
padding: "2rem",
textAlign: "center",
transform: isOpen ? "translateY(0)" : "translateY(2.5rem)",
opacity: isOpen ? 1 : 0,
transition: "transform 300ms ease, opacity 300ms ease"
},
children: [
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
"h2",
{
style: {
fontSize: "1.25rem",
lineHeight: "1.75rem",
fontWeight: 700,
color: "#1f2937",
margin: 0
},
children: [
"\u2757 ",
alarmText || "Alarm"
]
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
"p",
{
style: {
fontSize: "1rem",
lineHeight: "1.5rem",
color: "#374151",
marginTop: "1.5rem",
marginBottom: 0
},
children: message
}
),
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { marginTop: "1.5rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ConfirmButton, { onClick: onClose, children: confirmText || "Confirm" }) })
]
}
)
}
);
}
// src/ConfirmModal.tsx
var import_react2 = require("react");
var import_jsx_runtime3 = require("react/jsx-runtime");
function ConfirmModal({
isOpen,
message,
onYes,
onNo,
title = "Confirm",
yesText = "Yes",
noText = "No",
closeOnBackdrop = true
}) {
const [show, setShow] = (0, import_react2.useState)(false);
const titleId = (0, import_react2.useId)();
const descId = (0, import_react2.useId)();
const yesBtnRef = (0, import_react2.useRef)(null);
(0, import_react2.useEffect)(() => {
let timer;
if (isOpen) {
setShow(true);
} else {
timer = setTimeout(() => setShow(false), 300);
}
return () => timer && clearTimeout(timer);
}, [isOpen]);
(0, import_react2.useEffect)(() => {
if (isOpen) {
const t = setTimeout(() => yesBtnRef.current?.focus(), 50);
return () => clearTimeout(t);
}
}, [isOpen]);
(0, import_react2.useEffect)(() => {
if (!isOpen) return;
const onKey = (e) => {
if (e.key === "Escape") {
e.preventDefault();
onNo();
}
};
window.addEventListener("keydown", onKey);
return () => window.removeEventListener("keydown", onKey);
}, [isOpen, onNo]);
if (!isOpen && !show) return null;
const handleBackdropClick = () => {
if (closeOnBackdrop) onNo();
};
const overlayStyle = {
position: "fixed",
inset: 0,
background: "rgba(0, 0, 0, 0.4)",
backdropFilter: "blur(4px)",
display: "flex",
alignItems: "center",
justifyContent: "center",
zIndex: 50,
opacity: isOpen ? 1 : 0,
transition: "opacity 300ms ease"
};
const contentStyle = {
background: "#ffffff",
borderRadius: "12px",
boxShadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
width: "100%",
maxWidth: "28rem",
padding: "2rem",
textAlign: "center",
transform: isOpen ? "translateY(0)" : "translateY(2.5rem)",
opacity: isOpen ? 1 : 0,
transition: "transform 300ms ease, opacity 300ms ease"
};
const titleStyle = {
fontSize: "1.25rem",
lineHeight: "1.75rem",
fontWeight: 700,
color: "#1f2937",
margin: 0
};
const messageStyle = {
fontSize: "1rem",
lineHeight: "1.5rem",
color: "#374151",
marginTop: "1.5rem",
marginBottom: 0
};
const actionsStyle = {
marginTop: "1rem",
display: "flex",
alignItems: "center",
justifyContent: "center",
gap: "0.75rem"
};
const baseBtnStyle = {
display: "inline-flex",
alignItems: "center",
justifyContent: "center",
borderRadius: "0.5rem",
padding: "0.5rem 1rem",
fontSize: "1rem",
fontWeight: 500,
cursor: "pointer",
transition: "background 150ms ease, border-color 150ms ease, color 150ms ease",
outline: "none"
};
const yesBtnStyle = {
...baseBtnStyle,
color: "#fff",
background: "#2563eb",
border: "none"
};
const noBtnStyle = {
...baseBtnStyle,
color: "#374151",
background: "#fff",
border: "1px solid #d1d5db"
};
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"div",
{
style: overlayStyle,
onClick: handleBackdropClick,
role: "dialog",
"aria-modal": "true",
"aria-labelledby": titleId,
"aria-describedby": descId,
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { onClick: (e) => e.stopPropagation(), style: contentStyle, children: [
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { id: titleId, style: titleStyle, children: title }),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { id: descId, style: messageStyle, children: message }),
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: actionsStyle, children: [
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
"button",
{
ref: yesBtnRef,
type: "button",
onClick: onYes,
style: yesBtnStyle,
children: yesText
}
),
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", onClick: onNo, style: noBtnStyle, children: noText })
] })
] })
}
);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
AlertModal,
ConfirmModal
});
//# sourceMappingURL=index.cjs.map