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
116 lines (113 loc) • 4.21 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 PopoverContext = React.createContext(null);
const Popover = ({ children, open: controlledOpen, onOpenChange }) => {
const [uncontrolledOpen, setUncontrolledOpen] = React.useState(false);
const open = controlledOpen ?? uncontrolledOpen;
const setOpen = onOpenChange ?? setUncontrolledOpen;
const triggerRef = React.useRef(null);
const contentRef = React.useRef(null);
React.useEffect(() => {
const handleClickOutside = (event) => {
if (contentRef.current && triggerRef.current && !contentRef.current.contains(event.target) && !triggerRef.current.contains(event.target)) {
setOpen(false);
}
};
const handleEscape = (event) => {
if (event.key === "Escape") {
setOpen(false);
}
};
if (open) {
document.addEventListener("mousedown", handleClickOutside);
document.addEventListener("keydown", handleEscape);
}
return () => {
document.removeEventListener("mousedown", handleClickOutside);
document.removeEventListener("keydown", handleEscape);
};
}, [open, setOpen]);
return /* @__PURE__ */ jsxRuntimeExports.jsx(PopoverContext.Provider, { value: { open, setOpen, triggerRef, contentRef }, children });
};
const PopoverTrigger = React.forwardRef(
({ children, className, asChild, ...props }, forwardedRef) => {
const context = React.useContext(PopoverContext);
if (!context) throw new Error("PopoverTrigger must be used within Popover");
const { open, setOpen, triggerRef } = context;
const ref = React.useCallback(
(node) => {
if (node) {
triggerRef.current = node;
if (typeof forwardedRef === "function") forwardedRef(node);
else if (forwardedRef) forwardedRef.current = node;
}
},
[forwardedRef, triggerRef]
);
const Element = asChild ? React.Fragment : "button";
const elementProps = asChild ? {} : {
ref,
className: cn("inline-flex items-center justify-center", className),
onClick: () => setOpen(!open),
"aria-expanded": open,
"aria-haspopup": true,
...props
};
return /* @__PURE__ */ jsxRuntimeExports.jsx(Element, { ...elementProps, children });
}
);
const PopoverContent = React.forwardRef(
({ children, className, ...props }, forwardedRef) => {
const context = React.useContext(PopoverContext);
if (!context) throw new Error("PopoverContent must be used within Popover");
const { open, contentRef, triggerRef } = context;
const [position, setPosition] = React.useState({ top: 0, left: 0 });
React.useEffect(() => {
if (open && triggerRef.current) {
const rect = triggerRef.current.getBoundingClientRect();
setPosition({
top: rect.bottom + window.scrollY + 8,
left: rect.left + window.scrollX
});
}
}, [open]);
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;
},
style: {
position: "absolute",
top: position.top,
left: position.left
},
className: cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md",
"border border-[oklch(var(--theme-border))]",
"bg-[oklch(var(--theme-background))]",
"text-[oklch(var(--theme-foreground))]",
"shadow-md outline-none",
"animate-in fade-in-0 zoom-in-95",
className
),
role: "dialog",
"aria-modal": "true",
tabIndex: -1,
...props,
children
}
),
document.body
);
}
);
PopoverTrigger.displayName = "PopoverTrigger";
PopoverContent.displayName = "PopoverContent";
export { Popover, PopoverContent, PopoverTrigger };