UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

402 lines (389 loc) 8.97 kB
'use client'; import { jsx as i, jsxs as b } from "react/jsx-runtime"; import { useTheme as E } from "../../../theme/context.js"; import { css as t, keyframes as s } from "@emotion/react"; import n from "@emotion/styled"; import L, { useRef as w, useCallback as y, useEffect as u } from "react"; import { createPortal as q } from "react-dom"; const P = s` from { opacity: 0; } to { opacity: 1; } `, F = s` from { opacity: 1; } to { opacity: 0; } `, H = s` from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } `, N = s` from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.95); } `, T = (e) => { const { theme: o, size: r = "md" } = e; switch (r) { case "xs": return t` max-width: 320px; width: 90vw; `; case "sm": return t` max-width: 400px; width: 90vw; `; case "md": return t` max-width: 512px; width: 90vw; `; case "lg": return t` max-width: 640px; width: 90vw; `; case "xl": return t` max-width: 768px; width: 90vw; `; case "2xl": return t` max-width: 896px; width: 90vw; `; case "3xl": return t` max-width: 1024px; width: 90vw; `; case "4xl": return t` max-width: 1152px; width: 90vw; `; case "5xl": return t` max-width: 1280px; width: 90vw; `; case "full": return t` width: 100vw; height: 100vh; max-width: none; max-height: none; border-radius: 0; margin: 0; `; default: return t` max-width: 512px; width: 90vw; `; } }, W = (e) => { const { theme: o, radius: r = "lg", size: d } = e; if (d === "full") return t``; switch (r) { case "none": return t`border-radius: ${o.borderRadius.none};`; case "sm": return t`border-radius: ${o.borderRadius.sm};`; case "md": return t`border-radius: ${o.borderRadius.md};`; case "lg": return t`border-radius: ${o.borderRadius.lg};`; case "xl": return t`border-radius: ${o.borderRadius.xl};`; default: return t`border-radius: ${o.borderRadius.lg};`; } }, A = (e) => { const { placement: o = "center", size: r } = e; if (r === "full") return t` justify-content: center; align-items: center; `; switch (o) { case "top": return t` justify-content: flex-start; align-items: flex-start; padding-top: 3rem; `; case "top-center": return t` justify-content: center; align-items: flex-start; padding-top: 3rem; `; case "center": return t` justify-content: center; align-items: center; `; case "bottom": return t` justify-content: flex-start; align-items: flex-end; padding-bottom: 3rem; `; case "bottom-center": return t` justify-content: center; align-items: flex-end; padding-bottom: 3rem; `; default: return t` justify-content: center; align-items: center; @media (max-height: 640px) { align-items: flex-start; padding-top: 2rem; padding-bottom: 2rem; } `; } }, G = (e) => { const { theme: o, backdrop: r = "opaque" } = e; switch (r) { case "transparent": return t` background-color: transparent; `; case "opaque": return t` background-color: rgba(0, 0, 0, 0.5); `; case "blur": return t` background-color: rgba(0, 0, 0, 0.3); backdrop-filter: blur(4px); `; default: return t` background-color: rgba(0, 0, 0, 0.5); `; } }, J = n.div` position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: ${(e) => e.theme.zIndex.modal}; display: flex; padding: ${(e) => e.theme.spacing[4]}; animation: ${(e) => e.isClosing ? F : P} ${(e) => e.theme.transitions.normal}; ${G} ${A} /* Custom CSS prop */ ${(e) => e.css} `, K = n.div` position: relative; background-color: ${(e) => e.theme.colors.background.primary}; box-shadow: ${(e) => e.theme.shadows.xl}; display: flex; flex-direction: column; outline: none; animation: ${(e) => e.isClosing ? N : H} ${(e) => e.theme.transitions.normal}; ${T} ${W} ${(e) => e.scrollBehavior === "inside" && t` max-height: calc(100vh - 2 * ${e.theme.spacing[4]}); overflow: hidden; `} ${(e) => e.scrollBehavior === "outside" && t` max-height: none; overflow: visible; `} `, Q = n.button` position: absolute; top: ${(e) => e.theme.spacing[4]}; right: ${(e) => e.theme.spacing[4]}; background: none; border: none; cursor: pointer; padding: ${(e) => e.theme.spacing[2]}; border-radius: ${(e) => e.theme.borderRadius.sm}; color: ${(e) => e.theme.colors.text.secondary}; transition: all ${(e) => e.theme.transitions.fast}; z-index: 10; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; &:hover { background-color: ${(e) => e.theme.colors.neutral[100]}; color: ${(e) => e.theme.colors.text.primary}; } &:focus { outline: 2px solid ${(e) => e.theme.colors.border.focus}; outline-offset: 2px; } `, U = () => ( // biome-ignore lint/a11y/noSvgWithoutTitle: <explanation> /* @__PURE__ */ b( "svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [ /* @__PURE__ */ i("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), /* @__PURE__ */ i("line", { x1: "6", y1: "6", x2: "18", y2: "18" }) ] } ) ), V = L.forwardRef( ({ children: e, isOpen: o = !1, onClose: r, size: d = "md", radius: $ = "lg", placement: v = "auto", hideCloseButton: k = !1, isDismissable: h = !0, isKeyboardDismissDisabled: f = !1, scrollBehavior: c = "normal", backdrop: R = "opaque", className: j, css: C, portalContainer: M, ...S }, X) => { const { theme: p } = E(), l = w(null), g = w(null), m = y( (a) => { !f && a.key === "Escape" && o && r?.(); }, [o, r, f] ), z = y( (a) => { h && a.target === g.current && r?.(); }, [h, r] ); u(() => { o && l.current && l.current.focus(); }, [o]), u(() => { if (o && c !== "normal") { const a = window.getComputedStyle(document.body).overflow; return document.body.style.overflow = "hidden", () => { document.body.style.overflow = a; }; } }, [o, c]), u(() => { if (o) return document.addEventListener("keydown", m), () => document.removeEventListener("keydown", m); }, [o, m]); const x = { ...S, size: d, radius: $, placement: v, backdrop: R, scrollBehavior: c, className: j, theme: p, css: C }; if (!o) return null; const B = /* @__PURE__ */ i( J, { ref: g, onClick: z, ...x, children: /* @__PURE__ */ b( K, { ref: l, tabIndex: -1, role: "dialog", "aria-modal": "true", ...x, children: [ !k && /* @__PURE__ */ i( Q, { theme: p, onClick: r, "aria-label": "Close modal", children: /* @__PURE__ */ i(U, {}) } ), e ] } ) } ), I = M || document.body; return q(B, I); } ); V.displayName = "Modal"; const te = n.div` display: flex; flex-direction: column; gap: ${(e) => e.theme.spacing[2]}; padding: ${(e) => e.theme.spacing[6]} ${(e) => e.theme.spacing[6]} 0; padding-right: ${(e) => e.theme.spacing[12]}; /* Space for close button */ ${(e) => e.css} `, oe = n.div` display: flex; flex-direction: column; gap: ${(e) => e.theme.spacing[4]}; padding: ${(e) => e.theme.spacing[6]}; flex: 1; ${(e) => e.scrollBehavior === "inside" && t` overflow-y: auto; max-height: none; `} ${(e) => e.css} `, re = n.div` display: flex; flex-direction: row; justify-content: flex-end; align-items: center; gap: ${(e) => e.theme.spacing[3]}; padding: 0 ${(e) => e.theme.spacing[6]} ${(e) => e.theme.spacing[6]}; ${(e) => e.css} `; export { V as Modal, oe as ModalBody, re as ModalFooter, te as ModalHeader }; //# sourceMappingURL=modal.js.map