import { cn } from "@/lib/utils"; import * as DialogPrimitive from "@radix-ui/react-dialog"; import { XIcon } from "lucide-react"; import * as React from "react"; // Context to track composition state across dialog children const DialogCompositionContext = React.createContext<{ isComposing: () => boolean; setComposing: (composing: boolean) => void; justEndedComposing: () => boolean; markCompositionEnd: () => void; }>({ isComposing: () => false, setComposing: () => {}, justEndedComposing: () => false, markCompositionEnd: () => {}, }); export const useDialogComposition = () => React.useContext(DialogCompositionContext); function Dialog({ ...props }: React.ComponentProps) { const composingRef = React.useRef(false); const justEndedRef = React.useRef(false); const endTimerRef = React.useRef | null>(null); const contextValue = React.useMemo( () => ({ isComposing: () => composingRef.current, setComposing: (composing: boolean) => { composingRef.current = composing; }, justEndedComposing: () => justEndedRef.current, markCompositionEnd: () => { justEndedRef.current = true; if (endTimerRef.current) { clearTimeout(endTimerRef.current); } endTimerRef.current = setTimeout(() => { justEndedRef.current = false; }, 150); }, }), [] ); return ( ); } function DialogTrigger({ ...props }: React.ComponentProps) { return ; } function DialogPortal({ ...props }: React.ComponentProps) { return ; } function DialogClose({ ...props }: React.ComponentProps) { return ; } function DialogOverlay({ className, ...props }: React.ComponentProps) { return ( ); } DialogOverlay.displayName = "DialogOverlay"; function DialogContent({ className, children, showCloseButton = true, onEscapeKeyDown, ...props }: React.ComponentProps & { showCloseButton?: boolean; }) { const { isComposing } = useDialogComposition(); const handleEscapeKeyDown = React.useCallback( (e: KeyboardEvent) => { // Check both the native isComposing property and our context state // This handles Safari's timing issues with composition events const isCurrentlyComposing = (e as any).isComposing || isComposing(); // If IME is composing, prevent dialog from closing if (isCurrentlyComposing) { e.preventDefault(); return; } // Call user's onEscapeKeyDown if provided onEscapeKeyDown?.(e); }, [isComposing, onEscapeKeyDown] ); return ( {children} {showCloseButton && ( Close )} ); } function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { return (
); } function DialogFooter({ className, ...props }: React.ComponentProps<"div">) { return (
); } function DialogTitle({ className, ...props }: React.ComponentProps) { return ( ); } function DialogDescription({ className, ...props }: React.ComponentProps) { return ( ); } export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger };