"use client"; import * as React from "react"; import { cn } from "../../lib/utils"; import { X } from "lucide-react"; import { motion, AnimatePresence, HTMLMotionProps } from "framer-motion"; // Import motion, AnimatePresence, and HTMLMotionProps interface DialogContextType { open: boolean; setOpen: React.Dispatch>; } const DialogContext = React.createContext(undefined); interface DialogProps { children: React.ReactNode; defaultOpen?: boolean; open?: boolean; onOpenChange?: (open: boolean) => void; } const Dialog: React.FC = ({ children, defaultOpen = false, open: controlledOpen, onOpenChange, }) => { const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen); const isControlled = controlledOpen !== undefined; const open = isControlled ? controlledOpen : uncontrolledOpen; const setOpen = React.useCallback((value: boolean | ((prev: boolean) => boolean)) => { if (!isControlled) { setUncontrolledOpen(value); } if (onOpenChange) { const newValue = typeof value === "function" ? value(open) : value; onOpenChange(newValue); } }, [isControlled, onOpenChange, open]); return ( {children} ); }; interface DialogTriggerProps { children: React.ReactNode; asChild?: boolean; } const DialogTrigger = React.forwardRef>( ({ children, asChild = false, ...props }, ref) => { const context = React.useContext(DialogContext); if (!context) { throw new Error("DialogTrigger must be used within a Dialog"); } const { setOpen } = context; const handleClick = (e: React.MouseEvent) => { e.preventDefault(); setOpen(true); // Call the original onClick if it exists if (props.onClick) { props.onClick(e); } }; // Remove onClick from props to avoid duplicate handlers const { onClick, ...otherProps } = props; if (asChild) { return (
{React.Children.map(children, child => { if (React.isValidElement(child)) { return React.cloneElement(child, { ...child.props }); } return child; })}
); } return (
{children}
); } ); DialogTrigger.displayName = "DialogTrigger"; // Define a type that omits conflicting HTML attributes for Framer Motion type OmittedDialogContentHTMLAttributes = Omit, 'onAnimationStart' | 'onAnimationEnd' | 'onAnimationIteration' | 'onTransitionEnd' | 'onDrag' | 'onDragEnd' | 'onDragEnter' | 'onDragExit' | 'onDragLeave' | 'onDragOver' | 'onDragStart' | 'onDrop' | 'onMouseDown' | 'onMouseEnter' | 'onMouseLeave' | 'onMouseMove' | 'onMouseOut' | 'onMouseOver' | 'onMouseUp' | 'onTouchCancel' | 'onTouchEnd' | 'onTouchMove' | 'onTouchStart' | 'onPointerDown' | 'onPointerMove' | 'onPointerUp' | 'onPointerCancel' | 'onPointerEnter' | 'onPointerLeave' | 'onPointerOver' | 'onPointerOut' | 'onGotPointerCapture' | 'onLostPointerCapture' >; const DialogContent = React.forwardRef( // Use the new type here ({ className, children, ...props }, ref) => { const context = React.useContext(DialogContext); if (!context) { throw new Error("DialogContent must be used within a Dialog"); } const { open, setOpen } = context; return ( {open && ( // Conditionally render the motion components based on `open` state
{/* Backdrop Overlay */} setOpen(false)} // Close dialog when clicking overlay /> {/* Dialog Content */} to satisfy TypeScript {...props as HTMLMotionProps<'div'>} > {children}
)}
); } ); DialogContent.displayName = "DialogContent"; const DialogHeader = React.forwardRef>( ({ className, ...props }, ref) => (
) ); DialogHeader.displayName = "DialogHeader"; const DialogTitle = React.forwardRef>( ({ className, ...props }, ref) => (

) ); DialogTitle.displayName = "DialogTitle"; const DialogDescription = React.forwardRef>( ({ className, ...props }, ref) => (

) ); DialogDescription.displayName = "DialogDescription"; const DialogFooter = React.forwardRef>( ({ className, ...props }, ref) => (

) ); DialogFooter.displayName = "DialogFooter"; export { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter };