import * as React from "react"; import { cn } from "@/lib/utils"; import { VisuallyHidden } from "radix-ui"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, DrawerFooter, DrawerClose, } from "@/components/ui/drawer"; // --------------------------------------------------------------------------- // useMediaQuery // --------------------------------------------------------------------------- function useMediaQuery(query) { const [matches, setMatches] = React.useState(false); React.useEffect(() => { const mql = window.matchMedia(query); setMatches(mql.matches); const handler = (e) => setMatches(e.matches); mql.addEventListener("change", handler); return () => mql.removeEventListener("change", handler); }, [query]); return matches; } // --------------------------------------------------------------------------- // ResponsiveModal // // Props: // open boolean // onOpenChange (open: boolean) => void // // title ReactNode? — rendered as DialogTitle / DrawerTitle // description ReactNode? — rendered as DialogDescription / DrawerDescription // footer ReactNode? — rendered as DialogFooter / DrawerFooter // children ReactNode? — modal body // onAction - fetch api call // // dialogContentProps object? — forwarded to // drawerContentProps object? — forwarded to // drawerDirection "top"|"bottom"|"left"|"right" (default "bottom") // hideDrawerClose boolean? — hide the default Close button in drawer // // --------------------------------------------------------------------------- // Usage: // // // // // // } // > // // // // --------------------------------------------------------------------------- export function ResponsiveModal({ open, onOpenChange, title, description, footer, children, onAction, dialogContentProps = {}, drawerContentProps = {}, drawerDirection = "bottom", hideDrawerClose = false, }) { const isDesktop = useMediaQuery("(min-width: 768px)"); // ── Desktop → Dialog ────────────────────────────────────────────────── if (isDesktop) { return ( {title || description ? ( {title && {title}} {description && {description}} ) : ( )} {children} {(footer || onAction) && ( {footer} {onAction && ( )} )} ); } // ── Mobile → Drawer ─────────────────────────────────────────────────── return ( {title || description ? ( {title && {title}} {description ? ( {description} ) : ( )} ) : ( )}
{children}
{(footer || onAction || !hideDrawerClose) && ( {footer} {onAction && ( )} {!hideDrawerClose && ( )} )}
); } export { useMediaQuery }; export default ResponsiveModal; // =========================================================================== // USAGE EXAMPLES // =========================================================================== // // const [open, setOpen] = useState(false); // // // ── 1. Full example ─────────────────────────────────────────────────────── // // // // // // } // > // // // // // ── 2. Title only (no description) ─────────────────────────────────────── // // Delete} // > //

Are you sure?

//
// // // ── 3. No header ───────────────────────────────────────────────────────── // // //

Body only.

//
// // // ── 4. Custom width ─────────────────────────────────────────────────────── // // // // // // ===========================================================================