import clsx from 'clsx'; import React, { ReactNode, useEffect } from 'react'; import { MdArrowBackIosNew } from 'react-icons/md'; import { useEnv } from '@/context/EnvContext'; import { useDrag } from '@/hooks/useDrag'; import { useResponsiveSize } from '@/hooks/useResponsiveSize'; import { impactFeedback } from '@tauri-apps/plugin-haptics'; const VELOCITY_THRESHOLD = 0.5; interface DialogProps { id?: string; isOpen: boolean; children: ReactNode; header?: ReactNode; title?: string; className?: string; bgClassName?: string; boxClassName?: string; contentClassName?: string; onClose: () => void; } const Dialog: React.FC = ({ id, isOpen, children, header, title, className, bgClassName, boxClassName, contentClassName, onClose, }) => { const { appService } = useEnv(); const iconSize22 = useResponsiveSize(22); const isMobile = window.innerWidth < 640; const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'Escape') { onClose(); } }; useEffect(() => { window.addEventListener('keydown', handleKeyDown); return () => { window.removeEventListener('keydown', handleKeyDown); }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); const handleDragMove = (data: { clientY: number; deltaY: number }) => { if (!isMobile) return; const modal = document.querySelector('.modal-box') as HTMLElement; const overlay = document.querySelector('.overlay') as HTMLElement; const heightFraction = data.clientY / window.innerHeight; const newTop = Math.max(0.0, Math.min(1, heightFraction)); if (modal && overlay) { modal.style.transition = ''; modal.style.transform = `translateY(${newTop * 100}%)`; overlay.style.opacity = `${1 - heightFraction}`; } }; const handleDragEnd = (data: { velocity: number; clientY: number }) => { const modal = document.querySelector('.modal-box') as HTMLElement; const overlay = document.querySelector('.overlay') as HTMLElement; if (!modal || !overlay) return; if ( data.velocity > VELOCITY_THRESHOLD || (data.velocity >= 0 && data.clientY >= window.innerHeight * 0.5) ) { const transitionDuration = 0.15 / Math.max(data.velocity, 0.5); modal.style.transition = `transform ${transitionDuration}s ease-out`; modal.style.transform = 'translateY(100%)'; overlay.style.transition = `opacity ${transitionDuration}s ease-out`; overlay.style.opacity = '0'; setTimeout(() => { onClose(); modal.style.transform = 'translateY(0%)'; }, 300); if (appService?.hasHaptics) { impactFeedback('medium'); } } else { modal.style.transition = `transform 0.3s ease-out`; modal.style.transform = `translateY(0%)`; overlay.style.opacity = '0'; if (appService?.hasHaptics) { impactFeedback('medium'); } } }; const { handleDragStart } = useDrag(handleDragMove, handleDragEnd); return (
{window.innerWidth < 640 && (
)}
{header ? ( header ) : (
{title ?? ''}
)}
{children}
); }; export default Dialog;