UNPKG

@frank-auth/react

Version:

Flexible and customizable React UI components for Frank Authentication

347 lines (342 loc) 10.1 kB
'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