diff --git a/claudedocs/모달창_생성시_유의사항.md b/claudedocs/모달창_생성시_유의사항.md new file mode 100644 index 00000000..fa56c086 --- /dev/null +++ b/claudedocs/모달창_생성시_유의사항.md @@ -0,0 +1,233 @@ +# 모달창 생성 시 유의사항 + +## 개요 + +이 문서는 SAM 프로젝트에서 모달창을 구현할 때 발생할 수 있는 문제점과 해결 방법을 정리한 것입니다. + +--- + +## 1. pointer-events 문제 + +### 문제 상황 + +모달 배경 클릭을 방지하면서 모달 내부만 클릭 가능하게 하려고 다음과 같은 구조를 사용했을 때: + +```html + +
+
+
+
+ +
+
+
+``` + +**증상**: 모달은 표시되지만 내부의 버튼, 입력 필드 등 모든 요소가 클릭되지 않음 (마치 돌덩어리처럼 동작) + +### 원인 + +- `pointer-events-none`이 부모에 있고 `pointer-events-auto`가 자식에 있는 구조 +- AJAX로 로드된 내용이 `pointer-events-auto` div 안에 들어가도, 그 안의 요소들에 pointer-events가 제대로 상속되지 않을 수 있음 +- 특히 동적으로 로드된 HTML에서 이 문제가 자주 발생 + +### 해결 방법 + +`pointer-events-none/auto` 구조를 사용하지 않고 단순화: + +```html + + +``` + +--- + +## 2. AJAX로 로드된 HTML에서 함수 호출 문제 + +### 문제 상황 + +```html + + +``` + +**증상**: `closeModal is not defined` 오류 발생 + +### 원인 + +- 함수가 `function closeModal() {}` 형태로 정의되면 호이스팅되지만, 모듈 스코프나 블록 스코프 안에 있을 수 있음 +- AJAX로 로드된 HTML에서 전역 함수에 접근하지 못할 수 있음 + +### 해결 방법 + +**방법 1: window 객체에 명시적 등록** + +```javascript +// 전역 스코프에 함수 등록 +window.closeModal = function() { + document.getElementById('modal').classList.add('hidden'); + document.body.style.overflow = ''; +}; +``` + +**방법 2: 이벤트 델리게이션 (권장)** + +```html + + +``` + +```javascript +// JavaScript: document 레벨에서 이벤트 감지 +document.addEventListener('click', function(e) { + const closeBtn = e.target.closest('[data-close-modal]'); + if (closeBtn) { + e.preventDefault(); + window.closeModal(); + } +}); +``` + +--- + +## 3. 배경 스크롤 방지 + +### 모달 열 때 + +```javascript +document.body.style.overflow = 'hidden'; +``` + +### 모달 닫을 때 + +```javascript +document.body.style.overflow = ''; +``` + +--- + +## 4. ESC 키로 모달 닫기 + +```javascript +document.addEventListener('keydown', function(e) { + if (e.key === 'Escape') { + window.closeModal(); + } +}); +``` + +--- + +## 5. 완전한 모달 구현 예시 + +### HTML 구조 + +```html + + +``` + +### JavaScript + +```javascript +// 전역 함수 등록 +window.openExampleModal = function(id) { + const modal = document.getElementById('exampleModal'); + const content = document.getElementById('exampleModalContent'); + + modal.classList.remove('hidden'); + document.body.style.overflow = 'hidden'; + + // AJAX로 내용 로드 + fetch(`/api/example/${id}`) + .then(response => response.text()) + .then(html => { + content.innerHTML = html; + }); +}; + +window.closeExampleModal = function() { + document.getElementById('exampleModal').classList.add('hidden'); + document.body.style.overflow = ''; +}; + +// ESC 키 지원 +document.addEventListener('keydown', function(e) { + if (e.key === 'Escape') { + window.closeExampleModal(); + } +}); + +// 이벤트 델리게이션 (닫기 버튼) +document.addEventListener('click', function(e) { + if (e.target.closest('[data-close-modal]')) { + e.preventDefault(); + window.closeExampleModal(); + } +}); +``` + +### AJAX로 로드되는 부분 뷰 + +```html +
+
+

모달 제목

+ + +
+ + + +
+ + +
+
+``` + +--- + +## 6. 체크리스트 + +모달 구현 시 다음 사항을 확인하세요: + +- [ ] `pointer-events-none/auto` 구조를 사용하지 않음 +- [ ] 함수를 `window` 객체에 등록했음 +- [ ] 닫기 버튼에 `data-close-modal` 속성을 추가했음 +- [ ] document 레벨 이벤트 델리게이션을 설정했음 +- [ ] 모달 열 때 `body.style.overflow = 'hidden'` 설정 +- [ ] 모달 닫을 때 `body.style.overflow = ''` 복원 +- [ ] ESC 키 이벤트 리스너 등록 +- [ ] z-index가 다른 요소들과 충돌하지 않음 (보통 z-50 사용) + +--- + +## 관련 파일 + +- `/resources/views/sales/managers/index.blade.php` - 영업파트너 관리 모달 구현 예시 +- `/resources/views/sales/managers/partials/show-modal.blade.php` - 상세 모달 부분 뷰 +- `/resources/views/sales/managers/partials/edit-modal.blade.php` - 수정 모달 부분 뷰