nextuiq
Version:
NextUIQ is a modern, lightweight, and developer-friendly UI component library for React and Next.js. Built with TypeScript and Tailwind CSS, it offers customizable, accessible, and performance-optimized components with built-in dark mode, theme customizat
151 lines (148 loc) • 5.26 kB
JavaScript
import { j as jsxRuntimeExports } from './index46.mjs';
import * as React from 'react';
import { createPortal } from 'react-dom';
import { cn } from './index38.mjs';
const TooltipContext = React.createContext(null);
function Tooltip({
children,
content,
disabled = false,
delayDuration = 700,
side = "top",
// Add side prop
align = "center"
// Add align prop
}) {
const [open, setOpen] = React.useState(false);
const triggerRef = React.useRef(null);
const contentRef = React.useRef(null);
const timeoutRef = React.useRef(void 0);
const showTooltip = React.useCallback(() => {
if (disabled) return;
timeoutRef.current = window.setTimeout(() => setOpen(true), delayDuration);
}, [disabled, delayDuration]);
const hideTooltip = React.useCallback(() => {
if (timeoutRef.current) clearTimeout(timeoutRef.current);
setOpen(false);
}, []);
React.useEffect(() => {
return () => {
if (timeoutRef.current) clearTimeout(timeoutRef.current);
};
}, []);
return /* @__PURE__ */ jsxRuntimeExports.jsxs(TooltipContext.Provider, { value: { open, setOpen, triggerRef, contentRef, content }, children: [
/* @__PURE__ */ jsxRuntimeExports.jsx(
"div",
{
ref: triggerRef,
onMouseEnter: showTooltip,
onMouseLeave: hideTooltip,
onFocus: showTooltip,
onBlur: hideTooltip,
children
}
),
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { side, align, children: content })
] });
}
const TooltipContent = React.forwardRef(
({ children, className, side = "top", align = "center", ...props }, forwardedRef) => {
const context = React.useContext(TooltipContext);
if (!context) throw new Error("TooltipContent must be used within Tooltip");
const { open, contentRef, triggerRef, content } = context;
const [position, setPosition] = React.useState({ top: 0, left: 0 });
React.useEffect(() => {
if (open && triggerRef.current) {
const updatePosition = () => {
const rect = triggerRef.current?.getBoundingClientRect();
if (!rect) return;
const contentRect = contentRef.current?.getBoundingClientRect();
if (!contentRect) return;
const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
let top = 0;
let left = 0;
switch (side) {
case "top":
top = rect.top - contentRect.height - 8;
left = rect.left + (rect.width - contentRect.width) / 2;
if (top < 0) {
top = rect.bottom + 8;
}
break;
case "bottom":
top = rect.bottom + 8;
left = rect.left + (rect.width - contentRect.width) / 2;
if (top + contentRect.height > viewportHeight) {
top = rect.top - contentRect.height - 8;
}
break;
case "left":
top = rect.top + (rect.height - contentRect.height) / 2;
left = rect.left - contentRect.width - 8;
if (left < 0) {
left = rect.right + 8;
}
break;
case "right":
top = rect.top + (rect.height - contentRect.height) / 2;
left = rect.right + 8;
if (left + contentRect.width > viewportWidth) {
left = rect.left - contentRect.width - 8;
}
break;
}
left = Math.max(8, Math.min(left, viewportWidth - contentRect.width - 8));
setPosition({
top: top + window.scrollY,
left: left + window.scrollX
});
};
const handleScroll = () => {
requestAnimationFrame(updatePosition);
};
updatePosition();
window.addEventListener("resize", updatePosition);
window.addEventListener("scroll", handleScroll, true);
return () => {
window.removeEventListener("resize", updatePosition);
window.removeEventListener("scroll", handleScroll, true);
};
}
}, [open, side, align]);
if (!open || typeof document === "undefined") return null;
return createPortal(
/* @__PURE__ */ jsxRuntimeExports.jsx(
"div",
{
ref: (node) => {
contentRef.current = node;
if (typeof forwardedRef === "function") forwardedRef(node);
else if (forwardedRef) forwardedRef.current = node;
},
role: "tooltip",
style: {
position: "absolute",
top: position.top,
left: position.left
},
className: cn(
"z-[9999] max-w-xs overflow-hidden rounded-md",
// Updated z-index
"bg-[oklch(var(--theme-popover))]",
"px-3 py-1.5",
"text-sm text-[oklch(var(--theme-popover-foreground))]",
"shadow-md",
"animate-in fade-in-0 zoom-in-95",
className
),
...props,
children: children || content
}
),
document.body
);
}
);
TooltipContent.displayName = "TooltipContent";
export { Tooltip, TooltipContent };