All files / src/components/ui/modal/modal-content index.tsx

96.15% Statements 75/78
85.71% Branches 12/14
100% Functions 3/3
96.15% Lines 75/78

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 791x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 151x 7x 150x       7x 150x 1x 1x 1x 1x 1x 150x 6x 6x 1x 1x 1x 6x 151x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 57x 30x 30x 57x 57x 57x 57x 57x 57x 57x 57x  
'use client';
import { useEffect } from 'react';
 
import * as m from 'motion/react-m';
 
import { cn } from '@/lib/utils';
 
import { ModalCloseButton } from '../modal-close-button';
import { useModal } from '../modal-provider';
 
interface ModalContentProps {
  children: React.ReactNode;
  className?: string;
}
 
export const ModalContent = ({ children, className }: ModalContentProps) => {
  const { modalContentRef } = useModal();
 
  // focus trap 처리
  useEffect(() => {
    if (!modalContentRef.current) return;
 
    const modal = modalContentRef.current;
    const focusableElements = modal.querySelectorAll(
      'button:not([disabled]), a[href]:not([tabindex="-1"]), input:not([disabled]):not([tabindex="-1"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])',
    );
    const firstElement = focusableElements[0] as HTMLElement;
    const lastElement = focusableElements[focusableElements.length - 1] as HTMLElement;
 
    firstElement?.focus();
 
    const handleTab = (e: KeyboardEvent) => {
      if (e.key !== 'Tab') return;
 
      if (focusableElements.length === 0) {
        e.preventDefault();
        return;
      }
 
      if (e.shiftKey) {
        // Shift + Tab
        if (document.activeElement === firstElement) {
          e.preventDefault();
          lastElement?.focus();
        }
      } else {
        // Tab
        if (document.activeElement === lastElement) {
          e.preventDefault();
          firstElement?.focus();
        }
      }
    };
 
    modal.addEventListener('keydown', handleTab);
    return () => modal.removeEventListener('keydown', handleTab);
  }, [children, modalContentRef]);
 
  return (
    <m.div
      ref={modalContentRef}
      className={cn('w-full rounded-3xl bg-white p-5', className)}
      animate={{
        opacity: 1,
        scale: 1,
      }}
      initial={{ opacity: 0, scale: 0.1 }}
      onClick={(e) => {
        e.stopPropagation();
      }}
    >
      <div className='relative'>
        {children}
        <ModalCloseButton />
      </div>
    </m.div>
  );
};