import {
Dialog,
DialogActions,
DialogContent,
DialogContentProps,
DialogTitle,
DialogTitleProps,
DialogProps,
IconButton,
Stack,
SxProps,
Theme,
} from "@mui/material";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import React, { ReactNode } from "react";
/**
* ResponsiveDialog - A reusable dialog component that can switch between normal and expanded modes
*
* Features:
* - Normal mode: Dialog with customizable max-width (default 685px)
* - Expanded mode: Full height dialog (excluding app header) with centered content container
* - Fully customizable with sx props for Dialog, DialogTitle, and DialogContent
* - Preserves app header visibility in expanded mode
*
* @example
* ```tsx
* Save}
* contentSx={{ padding: 3 }}
* >
*
*
* ```
*/
interface ResponsiveDialogProps
extends Omit {
/** Whether the dialog is open */
open: boolean;
/** Callback fired when the dialog should be closed */
onClose: () => void;
/** Dialog title - can be string or custom ReactNode */
title: string | ReactNode;
/** Dialog content - form fields, text, etc. */
children: ReactNode;
/** Optional actions rendered in DialogActions (buttons, etc.) */
actions?: ReactNode;
/** Toggle between normal and expanded (fullscreen) mode */
isExpanded?: boolean;
/** Callback when expand/collapse button is clicked (required if using isExpanded) */
onExpandToggle?: () => void;
/** Max width in normal mode (default: "685px") */
normalMaxWidth?: string;
/** Max width of content container in expanded mode (default: "990px") */
expandedContentMaxWidth?: string;
/** Height of app header to preserve visibility (default: "90px") */
headerHeight?: string;
/** Spacing between children in normal mode (default: 2 = 16px) */
normalSpacing?: number;
/** Spacing between children in expanded mode (default: 3 = 24px) */
expandedSpacing?: number;
/** Custom styles for DialogContent - merged with base styles */
contentSx?: SxProps;
/** Custom styles for DialogTitle */
titleSx?: SxProps;
/** Additional props for DialogContent (excluding sx) */
dialogContentProps?: Omit;
/** Additional props for DialogTitle (excluding sx) */
dialogTitleProps?: Omit;
/** Whether to display dividers between title/content/actions */
dividers?: boolean;
}
function ResponsiveDialog({
open,
onClose,
title,
children,
actions,
isExpanded = false,
onExpandToggle,
normalMaxWidth = "685px",
expandedContentMaxWidth = "990px",
headerHeight = "90px",
normalSpacing = 2,
expandedSpacing = 3,
contentSx,
titleSx,
dialogContentProps,
dialogTitleProps,
dividers = false,
sx,
...otherDialogProps
}: ResponsiveDialogProps) {
const baseSx: SxProps = {
"& .MuiBackdrop-root": {
opacity: isExpanded ? "0 !important" : undefined,
transition: isExpanded ? "none !important" : undefined,
},
"& .MuiDialog-paper": {
maxWidth: isExpanded ? "100%" : normalMaxWidth,
width: "100%",
// height: isExpanded ? `calc(100vh - ${headerHeight})` : "90vh",
margin: isExpanded ? `${headerHeight} 0 0 0` : "32px",
maxHeight: isExpanded ? `calc(100vh - ${headerHeight})` : "790px",
boxShadow: isExpanded ? "none !important" : undefined,
transition: isExpanded ? "none !important" : undefined,
},
"& .MuiDialogActions-root .MuiBox-root": {
maxWidth: isExpanded ? expandedContentMaxWidth : undefined,
margin: isExpanded ? "0 auto" : undefined,
padding: isExpanded ? "0 12px" : undefined,
width: isExpanded ? "100%" : undefined,
justifyContent: isExpanded ? "flex-end" : undefined,
},
};
const baseContentSx: SxProps = {
width: "100%",
padding: isExpanded ? "16px" : undefined,
};
const contentWrapperSx: SxProps = {
maxWidth: isExpanded ? expandedContentMaxWidth : "100%",
margin: isExpanded ? "0 auto" : "0",
width: "100%",
};
const currentSpacing = isExpanded ? expandedSpacing : normalSpacing;
return (
);
}
export default ResponsiveDialog;