# 모달 필수 입력 검증 설계 ## 1. 목표 모든 모달에서 필수 입력값이 빈 상태로 저장 버튼을 클릭하면: - 첫 번째 빈 필수 필드로 포커스 이동 + 하이라이트 - 우측 상단에 토스트 알림 ("○○ 항목을 입력해주세요") - 버튼은 항상 활성 상태 (비활성화하지 않음) --- ## 2. 전체 구조 ``` ┌─────────────────────────────────────────────────────────────────┐ │ DialogContent (모든 모달의 공통 래퍼) │ │ │ │ useDialogAutoValidation(contentRef) │ │ │ │ │ ├─ 0단계: 모드 확인 │ │ │ └─ useTabStore.mode === "user" 일 때만 실행 │ │ │ │ │ ├─ 1단계: 필수 필드 탐지 │ │ │ └─ Label 내부 안에 * 문자 존재 여부 │ │ │ (라벨 텍스트 직접 매칭 X → span 태그 안의 * 만 감지) │ │ │ │ │ └─ 2단계: 저장 버튼 클릭 인터셉트 │ │ │ │ │ ├─ 저장/수정/확인 버튼 클릭 감지 │ │ │ (data-action-type="save"/"submit" │ │ │ 또는 data-variant="default") │ │ │ │ │ ├─ 빈 필수 필드 있음: │ │ │ ├─ 클릭 이벤트 차단 (stopPropagation + preventDefault) │ │ │ ├─ 첫 번째 빈 필드로 포커스 이동 │ │ │ ├─ 해당 필드 빨간 테두리 + 하이라이트 애니메이션 │ │ │ └─ 토스트 알림: "{필드명} 항목을 입력해주세요" │ │ │ │ │ └─ 모든 필수 필드 입력됨: │ │ └─ 클릭 이벤트 통과 (정상 저장 진행) │ │ │ │ 제외 조건: │ │ └─ 필수 필드가 0개인 모달 → 인터셉트 없음 │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## 3. 필수 필드 감지: span 기반 * 감지 ### 원리 화면 관리에서 필드를 "필수"로 체크하면 `component.required = true`가 저장된다. V2 컴포넌트가 렌더링할 때 `required = true`이면 Label 안에 `*`을 추가한다. 훅은 이 span 안의 `*`를 감지하여 필수 필드를 식별한다. ### 오탐 방지 관리자가 라벨 텍스트에 직접 `*`를 입력해도 span 안에 들어가지 않으므로 오탐이 발생하지 않는다. ``` required = true → → span 안에 * 있음 → 감지 O required = false → → span 없음 → 감지 X 라벨에 * 직접 입력 → → span 없이 텍스트에 * → 감지 X (오탐 방지) ``` ### 지원 필드 타입 | V2 컴포넌트 | 렌더링 요소 | 빈값 판정 | |---|---|---| | V2Input | ``, `