import clsx from "clsx"; import { X } from "lucide-react"; import type { ModalOverlayProps } from "react-aria-components"; import { Dialog, DialogTrigger, Heading, Modal, ModalOverlay, } from "react-aria-components"; import { useNavigate } from "react-router"; import * as R from "remeda"; import { SendouButton } from "~/components/elements/Button"; import styles from "./Dialog.module.css"; interface SendouDialogProps extends ModalOverlayProps { trigger?: React.ReactNode; children?: React.ReactNode; heading?: string; showHeading?: boolean; onClose?: () => void; /** When closing the modal which URL to navigate to */ onCloseTo?: string; overlayClassName?: string; "aria-label"?: string; /** If true, the modal takes over the full screen with the content below hidden */ isFullScreen?: boolean; /** If true, shows the close button even if onClose is not provided */ showCloseButton?: boolean; } /** * This component allows you to create a dialog with a customizable trigger and content. * It supports both controlled and uncontrolled modes for managing the dialog's open state. * * @example * // Example usage with implicit isOpen * return ( * * This is the dialog content. * * ); * * @example * // Example usage with a SendouButton as the trigger * return ( * Open Dialog} * > * This is the dialog content. * * ); */ export function SendouDialog({ trigger, children, ...rest }: SendouDialogProps) { if (!trigger) { const props = typeof rest.isOpen === "boolean" ? rest : { isOpen: true, ...rest }; return {children}; } return ( {trigger} {children} ); } function DialogModal({ children, heading, showHeading = true, className, showCloseButton: showCloseButtonProp, isControlledByTrigger, ...rest }: Omit & { isControlledByTrigger?: boolean }) { const navigate = useNavigate(); const showCloseButton = showCloseButtonProp || rest.onClose || rest.onCloseTo; const onClose = () => { if (rest.onCloseTo) { navigate(rest.onCloseTo); } else if (rest.onClose) { rest.onClose(); } }; const defaultOnOpenChange = (isOpen: boolean) => { if (!isOpen) { if (rest.onCloseTo) { navigate(rest.onCloseTo); } else if (rest.onClose) { rest.onClose(); } } }; const overlayProps = isControlledByTrigger ? R.omit(rest, ["onOpenChange"]) : { ...rest, onOpenChange: rest.onOpenChange ?? defaultOnOpenChange }; return ( {showHeading ? (
{heading ? ( {heading} ) : null} {showCloseButton ? ( } shape="circle" variant="minimal-destructive" className="ml-auto" slot="close" onPress={onClose} /> ) : null}
) : null} {children}
); }