@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
347 lines (342 loc) • 10.1 kB
JavaScript
'use client';
import { jsx as y } from "react/jsx-runtime";
import { useTheme as X } from "../../../theme/context.js";
import { keyframes as H, css as v } from "@emotion/react";
import z from "@emotion/styled";
import M, { useState as g, useRef as E, useCallback as V, useEffect as k } from "react";
import { createPortal as j } from "react-dom";
const D = [
"top",
"top-start",
"top-end",
"bottom",
"bottom-start",
"bottom-end",
"left",
"left-start",
"left-end",
"right",
"right-start",
"right-end"
], S = (e) => D.includes(e) ? e : "top", _ = H`
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
`, q = H`
from {
opacity: 1;
transform: scale(1);
}
to {
opacity: 0;
transform: scale(0.9);
}
`, G = (e, t, n, i) => {
if (!t) return {};
const u = S(e), o = {
position: "absolute",
zIndex: 1600
// Higher than popover
}, r = 8, a = Math.min(320, window.innerWidth - r * 2);
switch (u) {
case "top":
o.bottom = `${window.innerHeight - t.top + n}px`, o.left = `${t.left + t.width / 2}px`, o.transform = `translateX(-50%) translateX(${i}px)`, o.maxWidth = `${a}px`;
break;
case "top-start":
o.bottom = `${window.innerHeight - t.top + n}px`, o.left = `${Math.max(r, t.left + i)}px`, o.maxWidth = `${a}px`;
break;
case "top-end":
o.bottom = `${window.innerHeight - t.top + n}px`, o.right = `${Math.max(r, window.innerWidth - t.right - i)}px`, o.maxWidth = `${a}px`;
break;
case "bottom":
o.top = `${t.bottom + n}px`, o.left = `${t.left + t.width / 2}px`, o.transform = `translateX(-50%) translateX(${i}px)`, o.maxWidth = `${a}px`;
break;
case "bottom-start":
o.top = `${t.bottom + n}px`, o.left = `${Math.max(r, t.left + i)}px`, o.maxWidth = `${a}px`;
break;
case "bottom-end":
o.top = `${t.bottom + n}px`, o.right = `${Math.max(r, window.innerWidth - t.right - i)}px`, o.maxWidth = `${a}px`;
break;
case "left":
o.right = `${window.innerWidth - t.left + n}px`, o.top = `${t.top + t.height / 2}px`, o.transform = `translateY(-50%) translateY(${i}px)`, o.maxWidth = `${a}px`;
break;
case "left-start":
o.right = `${window.innerWidth - t.left + n}px`, o.top = `${Math.max(r, t.top + i)}px`, o.maxWidth = `${a}px`;
break;
case "left-end":
o.right = `${window.innerWidth - t.left + n}px`, o.bottom = `${Math.max(r, window.innerHeight - t.bottom - i)}px`, o.maxWidth = `${a}px`;
break;
case "right":
o.left = `${t.right + n}px`, o.top = `${t.top + t.height / 2}px`, o.transform = `translateY(-50%) translateY(${i}px)`, o.maxWidth = `${a}px`;
break;
case "right-start":
o.left = `${t.right + n}px`, o.top = `${Math.max(r, t.top + i)}px`, o.maxWidth = `${a}px`;
break;
case "right-end":
o.left = `${t.right + n}px`, o.bottom = `${Math.max(r, window.innerHeight - t.bottom - i)}px`, o.maxWidth = `${a}px`;
break;
default:
o.bottom = `${window.innerHeight - t.top + n}px`, o.left = `${t.left + t.width / 2}px`, o.transform = `translateX(-50%) translateX(${i}px)`, o.maxWidth = `${a}px`;
}
return o;
}, J = (e) => {
const t = S(e), n = 6;
switch (t) {
case "top":
case "top-start":
case "top-end":
return v`
&::after {
content: '';
position: absolute;
top: 100%;
left: ${t === "top" ? "50%" : t === "top-start" ? "12px" : "auto"};
right: ${t === "top-end" ? "12px" : "auto"};
transform: ${t === "top" ? "translateX(-50%)" : "none"};
width: 0;
height: 0;
border-left: ${n}px solid transparent;
border-right: ${n}px solid transparent;
border-top: ${n}px solid currentColor;
}
`;
case "bottom":
case "bottom-start":
case "bottom-end":
return v`
&::after {
content: '';
position: absolute;
bottom: 100%;
left: ${t === "bottom" ? "50%" : t === "bottom-start" ? "12px" : "auto"};
right: ${t === "bottom-end" ? "12px" : "auto"};
transform: ${t === "bottom" ? "translateX(-50%)" : "none"};
width: 0;
height: 0;
border-left: ${n}px solid transparent;
border-right: ${n}px solid transparent;
border-bottom: ${n}px solid currentColor;
}
`;
case "left":
case "left-start":
case "left-end":
return v`
&::after {
content: '';
position: absolute;
left: 100%;
top: ${t === "left" ? "50%" : t === "left-start" ? "12px" : "auto"};
bottom: ${t === "left-end" ? "12px" : "auto"};
transform: ${t === "left" ? "translateY(-50%)" : "none"};
width: 0;
height: 0;
border-top: ${n}px solid transparent;
border-bottom: ${n}px solid transparent;
border-left: ${n}px solid currentColor;
}
`;
case "right":
case "right-start":
case "right-end":
return v`
&::after {
content: '';
position: absolute;
right: 100%;
top: ${t === "right" ? "50%" : t === "right-start" ? "12px" : "auto"};
bottom: ${t === "right-end" ? "12px" : "auto"};
transform: ${t === "right" ? "translateY(-50%)" : "none"};
width: 0;
height: 0;
border-top: ${n}px solid transparent;
border-bottom: ${n}px solid transparent;
border-right: ${n}px solid currentColor;
}
`;
default:
return v``;
}
}, K = z.div`
background-color: ${(e) => e.theme.colors.neutral[800]};
color: ${(e) => e.theme.colors.neutral[50]};
border-radius: ${(e) => e.theme.borderRadius.md};
padding: ${(e) => e.theme.spacing[2]} ${(e) => e.theme.spacing[3]};
font-size: ${(e) => e.theme.fontSizes.sm};
line-height: ${(e) => e.theme.lineHeights.tight};
max-width: 320px;
word-wrap: break-word;
box-shadow: ${(e) => e.theme.shadows.md};
animation: ${(e) => e.isClosing ? q : _}
${(e) => e.theme.transitions.fast};
/* Arrow styles */
${(e) => e.showArrow && J(e.placement)}
/* Ensure arrow uses the same color as background */
&::after {
color: ${(e) => e.theme.colors.neutral[800]};
}
/* Custom CSS prop */
${(e) => e.css}
`, Q = z.div`
display: inline-block;
/* Custom CSS prop */
${(e) => e.css}
`, L = M.createContext(null), P = ({
children: e,
isOpen: t,
defaultOpen: n = !1,
onOpenChange: i,
placement: u = "top",
delay: o = 700,
closeDelay: r = 300,
showArrow: a = !0,
offset: l = 8,
crossOffset: w = 0,
isDisabled: p = !1,
className: f,
css: d,
portalContainer: h,
...c
}) => {
const [s, b] = g(n), T = E(null), x = t !== void 0, $ = x ? t : s, m = S(u), I = typeof o == "number" && o >= 0 ? o : 700, F = typeof r == "number" && r >= 0 ? r : 300, W = V(
(C) => {
p || (x || b(C), i?.(C));
},
[x, i, p]
);
k(() => {
if (!$ || p) return;
const C = (B) => {
B.key === "Escape" && W(!1);
};
return document.addEventListener("keydown", C), () => document.removeEventListener("keydown", C);
}, [$, W, p]);
const N = {
isOpen: $,
onOpenChange: W,
triggerRef: T,
placement: m,
showArrow: a,
offset: l,
crossOffset: w,
delay: I,
closeDelay: F,
isDisabled: p
};
return /* @__PURE__ */ y(L.Provider, { value: N, children: /* @__PURE__ */ y("div", { className: f, ...c, children: e }) });
}, A = ({
children: e,
className: t,
css: n,
"aria-label": i,
...u
}) => {
const { theme: o } = X(), r = M.useContext(L);
if (!r)
throw new Error("TooltipTrigger must be used within a Tooltip");
const { isOpen: a, onOpenChange: l, triggerRef: w, delay: p, closeDelay: f, isDisabled: d } = r, h = E(), c = E(), s = () => {
h.current && clearTimeout(h.current), c.current && clearTimeout(c.current);
}, b = () => {
d || (s(), h.current = setTimeout(() => {
l(!0);
}, p));
}, T = () => {
d || (s(), c.current = setTimeout(() => {
l(!1);
}, f));
}, x = () => {
d || (s(), l(!0));
}, $ = () => {
d || (s(), l(!1));
};
return k(() => () => s(), []), /* @__PURE__ */ y(
Q,
{
ref: w,
theme: o,
className: t,
css: n,
onMouseEnter: b,
onMouseLeave: T,
onFocus: x,
onBlur: $,
"aria-describedby": a ? "tooltip-content" : void 0,
"aria-label": i,
...u,
children: e
}
);
}, Y = ({
children: e,
className: t,
css: n,
...i
}) => {
const { theme: u } = X(), o = M.useContext(L);
if (!o)
throw new Error("TooltipContent must be used within a Tooltip");
const {
isOpen: r,
triggerRef: a,
placement: l,
showArrow: w,
offset: p,
crossOffset: f,
isDisabled: d
} = o, [h, c] = g(null), [s, b] = g(!1);
if (k(() => {
if (r && a.current && !d) {
const m = () => {
c(a.current.getBoundingClientRect());
};
return m(), window.addEventListener("scroll", m, !0), window.addEventListener("resize", m), () => {
window.removeEventListener("scroll", m, !0), window.removeEventListener("resize", m);
};
}
}, [r, a, d]), k(() => {
if (!r && h) {
b(!0);
const m = setTimeout(() => {
b(!1), c(null);
}, 150);
return () => clearTimeout(m);
}
}, [r, h]), !r && !s || d) return null;
const T = G(
l,
h,
p,
f
), x = document.body, $ = /* @__PURE__ */ y(
K,
{
id: "tooltip-content",
theme: u,
"data-tooltip-content": !0,
className: t,
css: n,
placement: l,
showArrow: w,
isClosing: s,
style: T,
role: "tooltip",
...i,
children: e
}
);
return j($, x);
};
P.Trigger = A;
P.Content = Y;
P.displayName = "Tooltip";
A.displayName = "TooltipTrigger";
Y.displayName = "TooltipContent";
export {
P as Tooltip
};
//# sourceMappingURL=tooltip.js.map