UNPKG

@divetocode/modal

Version:

A lightweight modal dialog system for React/Next.js

288 lines (283 loc) 8.58 kB
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