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 Card from '~/components/Card'; 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?.(); }} method={method ?? 'POST'} ref={ref} className={cn( 'outline-none rounded-3xl w-full max-w-lg', 'bg-white dark:bg-headplane-900', )} > {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 (