# 문제-해결 색인 > **용도**: "이전에 비슷한 문제 어떻게 해결했어?" > **검색 팁**: Ctrl+F로 키워드 검색 (에러 메시지, 컴포넌트명 등) --- ## 렌더링 관련 | 문제 | 해결 | 날짜 | 키워드 | |------|------|------|--------| | rowSpan이 적용 안됨 | gridTemplateRows를 `1fr`로 변경 | 2026-02-02 | grid, rowSpan, CSS | | 컴포넌트 크기 스케일 안됨 | viewportWidth 기반 scale 계산 추가 | 2026-02-04 | scale, viewport, 반응형 | | **그리드 가이드 셀 크기 불균일** | gridAutoRows → gridTemplateRows로 행 높이 강제 고정 | 2026-02-06 | gridAutoRows, gridTemplateRows, 셀 크기, CSS Grid | | **컴포넌트 콘텐츠가 셀 경계 벗어남** | overflow-visible → overflow-hidden 변경 | 2026-02-06 | overflow, 셀 크기, 콘텐츠 | ## DnD (드래그앤드롭) 관련 | 문제 | 해결 | 날짜 | 키워드 | |------|------|------|--------| | useDrag 에러 (뷰어에서) | isDesignMode 체크 후 early return | 2026-02-04 | DnD, useDrag, 뷰어 | | DndProvider 중복 에러 | 최상위에서만 Provider 사용 | 2026-02-04 | DndProvider, react-dnd | | **Expected drag drop context (뷰어)** | isDesignMode=false일 때 DraggableComponent 대신 일반 div 렌더링 | 2026-02-05 | DndProvider, useDrag, 뷰어, context | | **컴포넌트 중첩(겹침)** | toast import 누락 → `sonner`에서 import | 2026-02-05 | 겹침, overlap, toast | | **리사이즈 핸들 작동 안됨** | useDrop 2개 중복 → 단일 useDrop으로 통합 | 2026-02-05 | resize, 핸들, useDrop | | **드래그 좌표 완전 틀림 (Row 92)** | 캔버스 scale 보정 누락 → `(offset - rect.left) / scale` | 2026-02-05 | scale, 좌표, transform | | **DND 타입 상수 불일치** | 3개 파일에 중복 정의 → `constants/dnd.ts`로 통합 | 2026-02-05 | 상수, DND, 타입 | | **컴포넌트 이동 안됨** | useDrop accept 타입 불일치 → 공통 상수 사용 | 2026-02-05 | 이동, useDrop, accept | ## 타입 관련 | 문제 | 해결 | 날짜 | 키워드 | |------|------|------|--------| | 인터페이스 이름 불일치 | V5 접미사 제거, 통일 | 2026-02-05 | 타입, interface, Props | | v3/v4 타입 혼재 | v5 전용으로 통합, 레거시 삭제 | 2026-02-05 | 버전, 타입, 마이그레이션 | ## 레이아웃 관련 | 문제 | 해결 | 날짜 | 키워드 | |------|------|------|--------| | **화면 밖 컴포넌트 정보 손실** | 자동 줄바꿈 로직 추가 (col > maxCol → col=1, row=맨아래+1) | 2026-02-06 | 자동배치, 줄바꿈, 정보손실 | | Flexbox 배치 예측 불가 | CSS Grid로 전환 (v5) | 2026-02-05 | Flexbox, Grid, 반응형 | | 4모드 각각 배치 힘듦 | 제약조건 기반 시스템 (v4) | 2026-02-03 | 모드, 반응형, 제약조건 | | 4모드 자동 전환 안됨 | useResponsiveMode 훅 추가 | 2026-02-01 | 모드, 훅, 반응형 | ## 브레이크포인트/반응형 관련 | 문제 | 해결 | 날짜 | 키워드 | |------|------|------|--------| | **뷰어 반응형 모드 불일치** | detectGridMode() 사용으로 일관성 확보 | 2026-02-06 | 반응형, 뷰어, 모드 | | **768~839px 모드 불일치** | TABLET_MIN 768로 변경, 브레이크포인트 재설계 | 2026-02-06 | 브레이크포인트, 768px | | **useResponsiveMode vs GRID_BREAKPOINTS 불일치** | 뷰어에서 detectGridMode(viewportWidth) 사용 | 2026-02-06 | 훅, 상수, 일관성 | ## 저장/로드 관련 | 문제 | 해결 | 날짜 | 키워드 | |------|------|------|--------| | 레이아웃 버전 충돌 | isV5Layout 타입 가드로 분기 | 2026-02-05 | 버전, 로드, 타입가드 | | 빈 레이아웃 판별 실패 | components 존재 여부로 판별 | 2026-02-04 | 빈 레이아웃, 로드 | ## UI/UX 관련 | 문제 | 해결 | 날짜 | 키워드 | |------|------|------|--------| | root 레이아웃 오염 | tempLayout 도입 (임시 상태 분리) | 2026-02-04 | tempLayout, 상태, 오염 | | 속성 패널 다른 모드 수정 | isDefaultMode 체크로 비활성화 | 2026-02-04 | 속성패널, 모드, 비활성화 | --- ## 그리드 가이드 관련 | 문제 | 해결 | 날짜 | 키워드 | |------|------|------|--------| | SVG 격자와 CSS Grid 좌표 불일치 | GridGuide.tsx 삭제, PopRenderer에서 CSS Grid 셀로 격자 렌더링 | 2026-02-05 | 격자, SVG, CSS Grid, 좌표 | | 행/열 라벨 위치 오류 | PopCanvas에 absolute positioning 라벨 추가 | 2026-02-05 | 라벨, 행, 열, 정렬 | | 격자선과 컴포넌트 불일치 | 동일한 CSS Grid 좌표계 사용 | 2026-02-05 | 통합, 정렬, 일체감 | --- ## 해결 완료 (이번 세션) | 문제 | 상태 | 해결 방법 | |------|------|----------| | PopCanvas 타입 오류 | **해결** | 임시 타입 가드 추가 | | 팔레트 UI 없음 | **해결** | ComponentPalette.tsx 신규 추가 | | SVG 격자 좌표 불일치 | **해결** | CSS Grid 기반 통합 | | 드래그 좌표 완전 틀림 | **해결** | scale 보정 + calcGridPosition 함수 | | DND 타입 상수 불일치 | **해결** | constants/dnd.ts 통합 | | 컴포넌트 이동 안됨 | **해결** | useDrop/useDrag 타입 통일 | | 컴포넌트 중첩(겹침) | **해결** | toast import 추가 → 겹침 감지 로직 정상 작동 | | 리사이즈 핸들 작동 안됨 | **해결** | useDrop 통합 (2개 → 1개) | | 숨김 컴포넌트 드래그 안됨 | **해결** | handleMoveComponent에서 숨김 해제 + 위치 저장 단일 상태 업데이트 | | 그리드 범위 초과 에러 | **해결** | adjustedCol 계산으로 드롭 위치 자동 조정 | | Expected drag drop context (뷰어) | **해결** | isDesignMode=false일 때 일반 div 렌더링 | | hiddenComponentIds 중복 정의 | **해결** | 중복 useMemo 제거 (라인 410-412) | | 뷰어 반응형 모드 불일치 | **해결** | detectGridMode() 사용 | | 그리드 가이드 셀 크기 불균일 | **해결** | gridTemplateRows로 행 높이 강제 고정 | | Canvas vs Renderer 행 수 불일치 | **해결** | 숨김 필터 통일, 여유행 +3으로 통일 | | 디버깅 console.log 잔존 | **해결** | reviewComponents 내 console.log 삭제 | --- ## 드래그 좌표 버그 상세 (2026-02-05) ### 증상 - 컴포넌트를 아래로 드래그 → 위로 올라감 - Row 92 같은 비정상 좌표 - 드래그 이동/리사이즈 전혀 작동 안됨 ### 원인 ``` 캔버스: transform: scale(0.8) getBoundingClientRect() → 스케일 적용된 크기 (1024px → 819px) getClientOffset() → 뷰포트 기준 실제 마우스 좌표 이 둘을 그대로 계산하면 좌표 완전 틀림 ``` ### 해결 ```typescript // 스케일 보정된 상대 좌표 계산 const relX = (offset.x - canvasRect.left) / canvasScale; const relY = (offset.y - canvasRect.top) / canvasScale; // 실제 캔버스 크기로 그리드 계산 calcGridPosition(relX, relY, customWidth, ...); ``` ### 교훈 > CSS `transform: scale()` 적용된 요소에서 좌표 계산 시, > `getBoundingClientRect()`는 스케일 적용된 값을 반환하지만 > 마우스 좌표는 뷰포트 기준이므로 **반드시 스케일 보정 필요** --- ## Expected drag drop context 에러 상세 (2026-02-05 심야) ### 증상 ``` Invariant Violation: Expected drag drop context at useDrag (...) at DraggableComponent (...) ``` 뷰어 페이지(`/pop/viewer/[screenId]`)에서 POP 화면 조회 시 에러 발생 ### 원인 ``` PopRenderer의 DraggableComponent에서 useDrag 훅을 무조건 호출 → 뷰어 페이지에는 DndProvider가 없음 → React 훅은 조건부 호출 불가 (Rules of Hooks) → DndProvider 없이 useDrag 호출 시 context 에러 ``` ### 해결 ```typescript // PopRenderer.tsx - 컴포넌트 렌더링 부분 if (isDesignMode) { return ( // useDrag 사용 ); } // 뷰어 모드: 드래그 없는 일반 렌더링 return (
); ``` ### 교훈 > React DnD의 `useDrag`/`useDrop` 훅은 반드시 `DndProvider` 내부에서만 호출해야 함. > 디자인 모드와 뷰어 모드를 분기할 때, 훅이 포함된 컴포넌트 자체를 조건부 렌더링해야 함. > 훅 내부에서 `canDrag: false`로 설정해도 훅 자체는 호출되므로 context 에러 발생. ### 관련 파일 - `gridUtils.ts`: convertAndResolvePositions(), needsReview() - `PopCanvas.tsx`: ReviewPanel, ReviewItem - `PopRenderer.tsx`: 자동 배치 위치 렌더링 --- ## 뷰어 반응형 모드 불일치 상세 (2026-02-06) ### 증상 ``` - 아이폰 SE, iPad Pro 프리셋은 정상 작동 - 브라우저 수동 리사이즈 시 6칸 모드(mobile_landscape)가 적용 안 됨 - 768~839px 구간에서 8칸으로 표시됨 (예상: 6칸) ``` ### 원인 ``` useResponsiveMode 훅: - deviceType: width/height 비율로 "mobile"/"tablet" 판정 - isLandscape: width > height로 판정 - BREAKPOINTS.TABLET_MIN = 840 (당시) GRID_BREAKPOINTS: - mobile_landscape: 600~839px (6칸) - tablet_portrait: 840~1023px (8칸) 결과: - 768px 화면 → useResponsiveMode: "tablet" (768 < 840이지만 비율 판정) - 768px 화면 → GRID_BREAKPOINTS: "mobile_landscape" (6칸) - → 모드 불일치! ``` ### 해결 **1단계: 브레이크포인트 재설계** ```typescript // 기존 mobile_landscape: { minWidth: 600, maxWidth: 839 } tablet_portrait: { minWidth: 840, maxWidth: 1023 } // 변경 후 mobile_landscape: { minWidth: 480, maxWidth: 767 } tablet_portrait: { minWidth: 768, maxWidth: 1023 } ``` **2단계: 훅 연동** ```typescript // useDeviceOrientation.ts BREAKPOINTS.TABLET_MIN: 768 // was 840 ``` **3단계: 뷰어 모드 감지 방식 변경** ```typescript // page.tsx (뷰어) const currentModeKey = isPreviewMode ? getModeKey(deviceType, isLandscape) // 프리뷰: 수동 선택 : detectGridMode(viewportWidth); // 일반: 너비 기반 (일관성 확보) ``` ### 교훈 > 반응형 모드 판정은 **단일 소스(GRID_BREAKPOINTS)**를 기준으로 해야 함. > 훅과 상수가 각각 다른 기준을 사용하면 구간별 불일치 발생. > 뷰어에서는 `detectGridMode(viewportWidth)` 직접 사용으로 일관성 확보. --- ## 병합 관련 | 문제 | 해결 | 날짜 | 키워드 | |------|------|------|--------| | **ScreenDesigner.tsx 3건 충돌** (origin/main 병합) | 함수 시그니처: ksh-v2-work 유지(isPop/defaultDevicePreview), 저장 로직: 3단계 분기 유지+console.log 제거, 툴바 props: origin/main 채택 | 2026-02-09 | 병합, merge, ScreenDesigner, 충돌 | | **usePanelState 중복 선언** (병합 시 발견) | 충돌 1 해결 과정에서 L175의 중복 usePanelState 제거, L215의 완전한 버전만 유지 | 2026-02-09 | usePanelState, 중복, 병합 | | **툴바 JSX 들여쓰기 불일치** (병합 후 린트) | origin/main 코드가 ksh-v2-work와 2칸 들여쓰기 차이. 기능 영향 없음. 추후 포매팅 정리 권장 | 2026-02-09 | 들여쓰기, 포매팅, 린트, prettier | --- *새 문제-해결 추가 시 해당 카테고리 테이블에 행 추가*