import React, { cloneElement, useEffect, useRef } from "react"; import { type AriaDialogProps, type AriaModalOverlayProps, Overlay, useDialog, useModalOverlay, useOverlayTrigger, } from "react-aria"; import { Form, type HTMLFormMethod } from "react-router"; import { type OverlayTriggerProps, type OverlayTriggerState, useOverlayTriggerState, } from "react-stately"; import Button, { ButtonProps } from "~/components/Button"; import IconButton, { IconButtonProps } from "~/components/IconButton"; import Text from "~/components/Text"; import Title from "~/components/Title"; import cn from "~/utils/cn"; import { useLiveData } from "~/utils/live-data"; export interface DialogProps extends OverlayTriggerProps { children: | [ React.ReactElement | React.ReactElement, React.ReactElement, ] | React.ReactElement; } function Dialog(props: DialogProps) { const { pause, resume } = useLiveData(); const state = useOverlayTriggerState(props); const { triggerProps, overlayProps } = useOverlayTrigger( { type: "dialog", }, state, ); useEffect(() => { if (state.isOpen) { pause(); } else { resume(); } }, [state.isOpen]); if (Array.isArray(props.children)) { const [button, panel] = props.children; return ( <> {cloneElement(button, triggerProps)} {state.isOpen && ( {cloneElement(panel, { ...overlayProps, close: () => state.close(), })} )} ); } return ( {cloneElement(props.children, { ...overlayProps, close: () => state.close(), })} ); } export interface DialogPanelProps extends AriaDialogProps { children: React.ReactNode; variant?: "normal" | "destructive" | "unactionable"; onSubmit?: React.FormEventHandler; method?: HTMLFormMethod; isDisabled?: boolean; // Anonymous (passed by parent) close?: () => void; } function Panel(props: DialogPanelProps) { const { children, onSubmit, isDisabled, close, variant, method = "POST" } = props; const ref = useRef(null); const { dialogProps } = useDialog( { ...props, role: "alertdialog", }, ref, ); return (
{ if (onSubmit) { onSubmit(event); } close?.(); }} ref={ref} >
{children}
{variant === "unactionable" ? ( ) : ( <> )}
); } interface DModalProps extends AriaModalOverlayProps { children: React.ReactNode; state: OverlayTriggerState; } function DModal(props: DModalProps) { const { children, state } = props; const ref = useRef(null); const { modalProps, underlayProps } = useModalOverlay(props, state, ref); if (!state.isOpen) { return null; } return (