import { AlertDialog } from "@base-ui/react/alert-dialog"; import React, { cloneElement, useEffect, useRef } from "react"; import { Form, type HTMLFormMethod } from "react-router"; import Button, { type ButtonProps } from "~/components/button"; import cn from "~/utils/cn"; import { useLiveData } from "~/utils/live-data"; export interface DialogProps { children: | [React.ReactElement, React.ReactElement] | React.ReactElement; isOpen?: boolean; onOpenChange?: (isOpen: boolean) => void; } function Dialog(props: DialogProps) { const { pause, resume } = useLiveData(); const { isOpen, onOpenChange } = props; useEffect(() => { if (isOpen) { pause(); } else { resume(); } }, [isOpen]); if (Array.isArray(props.children)) { const [button, panel] = props.children; return ( onOpenChange?.(open)}> {panel} ); } return ( onOpenChange?.(open)}> {props.children} ); } export interface DialogPanelProps { children: React.ReactNode; variant?: "normal" | "destructive" | "unactionable"; onSubmit?: React.FormEventHandler; method?: HTMLFormMethod; isDisabled?: boolean; } function Panel(props: DialogPanelProps) { const { children, onSubmit, isDisabled, variant, method = "POST" } = props; const closeRef = useRef(null); return (
{ if (onSubmit) { onSubmit(event); } if (!event.defaultPrevented) { closeRef.current?.click(); } }} > {/* px-1 -mx-1 gives focus rings on inputs/buttons room to render without being clipped by overflow-y-auto (which implicitly forces overflow-x: auto per CSS spec). */}
{children}
{variant === "unactionable" ? ( Close} /> ) : ( <> Cancel} /> )}
); } function DialogOverlay({ children }: { children: React.ReactNode }) { return (
{children}
); } export { Panel as DialogPanel }; export default Dialog;