@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
334 lines (329 loc) • 9.31 kB
JavaScript
'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