import { useEffect, useId, useRef, type CSSProperties, type ReactNode } from "react"; import { createPortal } from "react-dom"; import { translateReactNode, usePlatformLanguage } from "../i18n/LanguageContext"; import { shouldCloseDialogOnBackdrop } from "./dialogInteractions"; import { dialogIsTopmost, nextDialogActivationOrder, registerDialog, type DialogStackId } from "./dialogStack"; import type { PlatformInterfaceIdentityProps } from "../types"; import { DialogActions, type DialogActionAlignment } from "./DialogAnatomy"; export type DialogSize = "small" | "default" | "large" | "wide" | "full"; export type DialogVariant = "default" | "administration"; export type DialogBodyPadding = "none" | "compact" | "default"; export type DialogProps = PlatformInterfaceIdentityProps & { open: boolean; title: ReactNode; children: ReactNode; footer?: ReactNode; description?: ReactNode; notices?: ReactNode; size?: DialogSize; variant?: DialogVariant; bodyPadding?: DialogBodyPadding; footerAlignment?: DialogActionAlignment; role?: "dialog" | "alertdialog"; ariaDescribedBy?: string; closeLabel?: string; closeOnBackdrop?: boolean; showCloseButton?: boolean; closeDisabled?: boolean; onClose?: () => void; className?: string; backdropClassName?: string; headerClassName?: string; titleClassName?: string; bodyClassName?: string; footerClassName?: string; portal?: boolean; panelStyle?: CSSProperties; backdropStyle?: CSSProperties; }; function joinClasses(...classes: Array) { return classes.filter(Boolean).join(" "); } export default function Dialog({ open, title, children, footer, description, notices, size = "default", variant = "default", bodyPadding = "default", footerAlignment = "end", role = "dialog", ariaDescribedBy, closeLabel = "i18n:govoplan-core.close.bbfa773e", closeOnBackdrop = true, showCloseButton = true, closeDisabled = false, onClose, className = "", backdropClassName = "", headerClassName = "", titleClassName = "", bodyClassName = "", footerClassName = "", portal = false, panelStyle, backdropStyle, interfaceId, helpContextId, helpModuleId, helpTopicId }: DialogProps) { const titleId = useId(); const canClose = Boolean(onClose) && !closeDisabled; const panelRef = useRef(null); const stackIdRef = useRef(Symbol("govoplan-dialog")); const activationOrderRef = useRef(null); const canCloseRef = useRef(canClose); const onCloseRef = useRef(onClose); const restoreFocusRef = useRef( typeof document !== "undefined" && typeof HTMLElement !== "undefined" && document.activeElement instanceof HTMLElement ? document.activeElement : null ); canCloseRef.current = canClose; onCloseRef.current = onClose; if (!open) activationOrderRef.current = null; else if (activationOrderRef.current === null) activationOrderRef.current = nextDialogActivationOrder(); const { translateText } = usePlatformLanguage(); const renderedTitle = translateReactNode(title, translateText); const renderedChildren = translateReactNode(children, translateText); const renderedFooter = translateReactNode(footer, translateText); const renderedDescription = translateReactNode(description, translateText); const renderedNotices = translateReactNode(notices, translateText); const translatedCloseLabel = translateText(closeLabel); useEffect(() => { if (open || typeof document === "undefined") return undefined; const rememberFocusedElement = () => { const activeElement = document.activeElement; if (!(activeElement instanceof HTMLElement)) return; if (panelRef.current?.contains(activeElement)) return; restoreFocusRef.current = activeElement; }; rememberFocusedElement(); document.addEventListener("focusin", rememberFocusedElement); return () => document.removeEventListener("focusin", rememberFocusedElement); }, [open]); useEffect(() => { if (!open || typeof document === "undefined") return undefined; const panel = panelRef.current; const activationOrder = activationOrderRef.current; if (!panel || activationOrder === null) return undefined; return registerDialog({ id: stackIdRef.current, activationOrder, panel, restoreFocus: restoreFocusRef.current, canClose: () => canCloseRef.current, onClose: () => onCloseRef.current?.() }, document.activeElement); }, [open]); if (!open) return null; const dialog = (
{ if ( dialogIsTopmost(stackIdRef.current) && shouldCloseDialogOnBackdrop(event.target, event.currentTarget, closeOnBackdrop, canClose) ) onClose?.(); }} >

{renderedTitle}

{showCloseButton && onClose && ( )}
{description &&
{renderedDescription}
} {notices &&
{renderedNotices}
} {renderedChildren}
{footer &&
{renderedFooter}
}
); return portal && typeof document !== "undefined" ? createPortal(dialog, document.body) : dialog; }