import { Button } from "@repo/shadcn-ui/components/button"; import { Dialog, DialogClose, DialogContent, DialogFooter, DialogHeader, DialogTitle, } from "@repo/shadcn-ui/components/dialog"; import type { ComponentProps, ReactNode } from "react"; import { createContext, useContext, useRef } from "react"; type FormDialogLayout = "content" | "stable" | "picker"; const FormLayoutContext = createContext("content"); const FormCancelContext = createContext(undefined); export function FormDialog({ open, onOpenChange, title, cancelLabel, children, wide = false, size, formActions = false, layout = "content", finalFocus, }: { open: boolean; onOpenChange: (open: boolean) => void; title: ReactNode; cancelLabel: string; children: ReactNode; wide?: boolean; size?: "small" | "medium" | "large"; formActions?: boolean; layout?: FormDialogLayout; finalFocus?: ComponentProps["finalFocus"]; }) { const popupRef = useRef(null); const width = size ?? (wide ? "large" : "small"); const widths = { small: "sm:max-w-xl", medium: "sm:max-w-3xl", large: "sm:w-[90vw] sm:max-w-[1200px]", }; // La altura de los diálogos dinámicos depende de la ventana, nunca de sus resultados o pasos. const height = layout === "content" ? "" : "h-[calc(100dvh-2rem)] sm:h-[min(85dvh,900px)]"; return ( popupRef.current?.querySelector("input[data-quick-search]") ?? true : undefined } ref={popupRef} showCloseButton={true} > {title}
{children}
{!formActions && ( }> {cancelLabel} )}
); } export function FormActions({ children, leadingActions, cancelDisabled = false, }: { children: ReactNode; leadingActions?: ReactNode; cancelDisabled?: boolean; }) { const cancelLabel = useContext(FormCancelContext); const layout = useContext(FormLayoutContext); return ( button]:flex-1 sm:[&>button]:flex-none" : "py-4"}`} > {leadingActions && (
{leadingActions}
)} {cancelLabel && ( }> {cancelLabel} )} {children}
); } /** El cuerpo reserva espacio simétrico para que el scroll no recorte el anillo de foco. */ export function FormBody({ children, contentLayout = "stack", }: { children: ReactNode; contentLayout?: "stack" | "fill"; }) { const layout = useContext(FormLayoutContext); const fills = layout === "picker" || contentLayout === "fill"; return (
p]:shrink-0" : `overflow-y-auto pt-1 pb-5 ${fills ? "flex flex-col gap-5 [&>*]:shrink-0" : "space-y-5"}`} ${layout === "content" ? "" : "[scrollbar-gutter:stable]"}`} data-slot="form-body" > {children}
); }