@coin-voyage/paykit
Version:
Seamless crypto payments. Onboard users from any chain, any coin into your app with one click.
83 lines (82 loc) • 4.5 kB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import { useEffect, useRef, useState } from "react";
import useMeasure from "react-use-measure";
import usePayContext from "../../contexts/pay";
import { TooltipContainer, TooltipTail, TooltipWindow } from "./styles";
import { AnimatePresence, motion, useIsomorphicLayoutEffect } from "framer-motion";
import { useThemeContext } from "../../../providers/theme/provider";
import { ResetContainer } from "../../../styles";
import Portal from "../Portal";
export default function Tooltip({ children, message, open, xOffset = 0, yOffset = 0, delay }) {
const context = usePayContext();
const themeContext = useThemeContext();
const [isOpen, setIsOpen] = useState(false);
const [outOfBounds, setOutOfBounds] = useState(false);
const [size, setSize] = useState("small");
const [ready, setReady] = useState(false);
const [currentRoute] = useState(context.route);
const targetRef = useRef(null);
const [ref, bounds] = useMeasure({
debounce: !ready ? 220 : 0,
offsetSize: true,
scroll: true,
});
const checkBounds = () => {
const x = xOffset + bounds.left + bounds.width;
const y = yOffset + bounds.top + bounds.height * 0.5;
return x > window.innerWidth || x < 0 || y > window.innerHeight || y < 0;
};
const refreshLayout = () => {
if (!targetRef.current ||
bounds.top + bounds.bottom + bounds.left + bounds.right + bounds.height + bounds.width === 0) {
return;
}
const x = xOffset + bounds.left + bounds.width;
const y = yOffset + bounds.top + bounds.height * 0.5;
if (!ready && x !== 0 && y !== 0) {
window.requestAnimationFrame(() => setReady(true));
}
targetRef.current.style.left = `${x}px`;
targetRef.current.style.top = `${y}px`;
setSize(targetRef.current.offsetHeight <= 40 ? "small" : "large");
setOutOfBounds(checkBounds());
};
useIsomorphicLayoutEffect(refreshLayout, [bounds, open, isOpen]);
useEffect(() => {
if (!context.open) {
window.requestAnimationFrame(() => {
setIsOpen(false);
});
}
}, [context.open]);
useEffect(() => {
window.requestAnimationFrame(() => {
setIsOpen(!!open);
});
}, [open]);
const shouldRenderTooltip = !context.options?.hideTooltips;
return (_jsxs(_Fragment, { children: [_jsx(motion.div, { ref: ref, style: open === undefined ? { cursor: "help" } : {}, onHoverStart: () => setIsOpen(true), onHoverEnd: () => setIsOpen(false), onClick: () => setIsOpen(false), children: children }), shouldRenderTooltip && (_jsx(Portal, { children: _jsx(AnimatePresence, { children: currentRoute === context.route && !outOfBounds && isOpen && (_jsx(ResetContainer, { "$useTheme": themeContext.theme, "$useMode": themeContext.mode, "$customTheme": themeContext.customTheme, children: _jsx(TooltipWindow, { children: _jsxs(TooltipContainer, { role: "tooltip", "$size": size, ref: targetRef, initial: "collapsed", animate: ready ? "open" : {}, exit: "collapsed", variants: {
collapsed: {
transformOrigin: "20px 50%",
opacity: 0,
scale: 0.9,
z: 0.01,
y: "-50%",
x: 20,
transition: { duration: 0.1 },
},
open: {
willChange: "opacity,transform",
opacity: 1,
scale: 1,
z: 0.01,
y: "-50%",
x: 20,
transition: {
ease: [0.76, 0, 0.24, 1],
duration: 0.15,
delay: delay ?? 0.5,
},
},
}, children: [message, _jsx(TooltipTail, { "$size": size })] }) }) })) }) }))] }));
}