UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

334 lines (329 loc) 9.31 kB
'use client'; import { jsx as m, jsxs as A, Fragment as I } from "react/jsx-runtime"; import { useTheme as L } from "../../../theme/context.js"; import { keyframes as T, css as s } from "@emotion/react"; import P from "@emotion/styled"; import z, { useState as M, useRef as N, useCallback as j, useEffect as g } from "react"; import { createPortal as q } from "react-dom"; const V = T` from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } `, D = T` from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.95); } `, G = (t, o, r, n) => { if (!o) return {}; const e = { position: "absolute", zIndex: 1500 }; switch (t) { case "top": e.bottom = `${window.innerHeight - o.top + r}px`, e.left = `${o.left + o.width / 2}px`, e.transform = `translateX(-50%) translateX(${n}px)`; break; case "top-start": e.bottom = `${window.innerHeight - o.top + r}px`, e.left = `${o.left + n}px`; break; case "top-end": e.bottom = `${window.innerHeight - o.top + r}px`, e.right = `${window.innerWidth - o.right - n}px`; break; case "bottom": e.top = `${o.bottom + r}px`, e.left = `${o.left + o.width / 2}px`, e.transform = `translateX(-50%) translateX(${n}px)`; break; case "bottom-start": e.top = `${o.bottom + r}px`, e.left = `${o.left + n}px`; break; case "bottom-end": e.top = `${o.bottom + r}px`, e.right = `${window.innerWidth - o.right - n}px`; break; case "left": e.right = `${window.innerWidth - o.left + r}px`, e.top = `${o.top + o.height / 2}px`, e.transform = `translateY(-50%) translateY(${n}px)`; break; case "left-start": e.right = `${window.innerWidth - o.left + r}px`, e.top = `${o.top + n}px`; break; case "left-end": e.right = `${window.innerWidth - o.left + r}px`, e.bottom = `${window.innerHeight - o.bottom - n}px`; break; case "right": e.left = `${o.right + r}px`, e.top = `${o.top + o.height / 2}px`, e.transform = `translateY(-50%) translateY(${n}px)`; break; case "right-start": e.left = `${o.right + r}px`, e.top = `${o.top + n}px`; break; case "right-end": e.left = `${o.right + r}px`, e.bottom = `${window.innerHeight - o.bottom - n}px`; break; default: e.top = `${o.bottom + r}px`, e.left = `${o.left + o.width / 2}px`, e.transform = `translateX(-50%) translateX(${n}px)`; } return e; }, J = (t) => { switch (t) { case "top": case "top-start": case "top-end": return s` &::after { content: ''; position: absolute; top: 100%; left: ${t === "top" ? "50%" : t === "top-start" ? "16px" : "auto"}; right: ${t === "top-end" ? "16px" : "auto"}; transform: ${t === "top" ? "translateX(-50%)" : "none"}; width: 0; height: 0; border-left: ${8}px solid transparent; border-right: ${8}px solid transparent; border-top: ${8}px solid currentColor; } `; case "bottom": case "bottom-start": case "bottom-end": return s` &::after { content: ''; position: absolute; bottom: 100%; left: ${t === "bottom" ? "50%" : t === "bottom-start" ? "16px" : "auto"}; right: ${t === "bottom-end" ? "16px" : "auto"}; transform: ${t === "bottom" ? "translateX(-50%)" : "none"}; width: 0; height: 0; border-left: ${8}px solid transparent; border-right: ${8}px solid transparent; border-bottom: ${8}px solid currentColor; } `; case "left": case "left-start": case "left-end": return s` &::after { content: ''; position: absolute; left: 100%; top: ${t === "left" ? "50%" : t === "left-start" ? "16px" : "auto"}; bottom: ${t === "left-end" ? "16px" : "auto"}; transform: ${t === "left" ? "translateY(-50%)" : "none"}; width: 0; height: 0; border-top: ${8}px solid transparent; border-bottom: ${8}px solid transparent; border-left: ${8}px solid currentColor; } `; case "right": case "right-start": case "right-end": return s` &::after { content: ''; position: absolute; right: 100%; top: ${t === "right" ? "50%" : t === "right-start" ? "16px" : "auto"}; bottom: ${t === "right-end" ? "16px" : "auto"}; transform: ${t === "right" ? "translateY(-50%)" : "none"}; width: 0; height: 0; border-top: ${8}px solid transparent; border-bottom: ${8}px solid transparent; border-right: ${8}px solid currentColor; } `; default: return s``; } }, K = (t) => { const { theme: o, backdrop: r = "transparent" } = t; switch (r) { case "transparent": return s` background-color: transparent; `; case "opaque": return s` background-color: rgba(0, 0, 0, 0.1); `; case "blur": return s` background-color: rgba(0, 0, 0, 0.05); backdrop-filter: blur(2px); `; default: return s` background-color: transparent; `; } }, Q = P.div` position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: ${(t) => t.theme.zIndex.overlay}; ${K} `, U = P.div` background-color: ${(t) => t.theme.colors.background.primary}; border: 1px solid ${(t) => t.theme.colors.border.primary}; border-radius: ${(t) => t.theme.borderRadius.lg}; box-shadow: ${(t) => t.theme.shadows.lg}; padding: ${(t) => t.theme.spacing[4]}; max-width: 320px; animation: ${(t) => t.isClosing ? D : V} ${(t) => t.theme.transitions.fast}; color: ${(t) => t.theme.colors.background.primary}; ${(t) => t.showArrow && J(t.placement)} /* Custom CSS prop */ ${(t) => t.css} `, Z = P.div` display: inline-block; cursor: pointer; /* Custom CSS prop */ ${(t) => t.css} `, E = z.createContext(null), X = ({ children: t, isOpen: o, defaultOpen: r = !1, onOpenChange: n, placement: e = "bottom", trigger: i = "click", showArrow: d = !0, offset: a = 8, crossOffset: u = 0, shouldCloseOnBlur: p = !0, shouldCloseOnInteractOutside: c = !0, backdrop: w = "transparent", className: x, css: f, portalContainer: k, ...v }) => { const [C, W] = M(r), y = N(null), S = o !== void 0, h = S ? o : C, b = j( (l) => { S || W(l), n?.(l); }, [S, n] ); g(() => { if (!h || !c) return; const l = ($) => { if (y.current && !y.current.contains($.target)) { const B = document.querySelector("[data-popover-content]"); B && !B.contains($.target) && b(!1); } }; return document.addEventListener("mousedown", l), () => document.removeEventListener("mousedown", l); }, [h, c, b]), g(() => { if (!h) return; const l = ($) => { $.key === "Escape" && b(!1); }; return document.addEventListener("keydown", l), () => document.removeEventListener("keydown", l); }, [h, b]); const F = { isOpen: h, onOpenChange: b, triggerRef: y, placement: e, trigger: i, showArrow: d, offset: a, crossOffset: u }; return /* @__PURE__ */ m(E.Provider, { value: F, children: /* @__PURE__ */ m("div", { className: x, ...v, children: t }) }); }, Y = ({ children: t, className: o, css: r, ...n }) => { const { theme: e } = L(), i = z.useContext(E); if (!i) throw new Error("PopoverTrigger must be used within a Popover"); const { isOpen: d, onOpenChange: a, triggerRef: u, trigger: p } = i; return /* @__PURE__ */ m( Z, { ref: u, theme: e, className: o, css: r, onClick: () => { p === "click" && a(!d); }, onMouseEnter: () => { p === "hover" && a(!0); }, onMouseLeave: () => { p === "hover" && a(!1); }, onFocus: () => { p === "focus" && a(!0); }, onBlur: () => { p === "focus" && a(!1); }, ...n, children: t } ); }, H = ({ children: t, className: o, css: r, ...n }) => { const { theme: e } = L(), i = z.useContext(E); if (!i) throw new Error("PopoverContent must be used within a Popover"); const { isOpen: d, triggerRef: a, placement: u, showArrow: p, offset: c, crossOffset: w } = i, [x, f] = M(null); if (g(() => { d && a.current && f(a.current.getBoundingClientRect()); }, [d, a]), !d) return null; const k = G( u, x, c, w ), v = document.body, C = /* @__PURE__ */ A(I, { children: [ i && /* @__PURE__ */ m(Q, { theme: e }), /* @__PURE__ */ m( U, { theme: e, "data-popover-content": !0, className: o, css: r, placement: u, showArrow: p, style: k, ...n, children: t } ) ] }); return q(C, v); }; X.Trigger = Y; X.Content = H; X.displayName = "Popover"; Y.displayName = "PopoverTrigger"; H.displayName = "PopoverContent"; export { X as Popover }; //# sourceMappingURL=popover.js.map