255 lines
11 KiB
Markdown
255 lines
11 KiB
Markdown
# 문제-해결 색인
|
|
|
|
> **용도**: "이전에 비슷한 문제 어떻게 해결했어?"
|
|
> **검색 팁**: 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 (
|
|
<DraggableComponent ... /> // useDrag 사용
|
|
);
|
|
}
|
|
|
|
// 뷰어 모드: 드래그 없는 일반 렌더링
|
|
return (
|
|
<div className="..." style={positionStyle}>
|
|
<ComponentContent ... />
|
|
</div>
|
|
);
|
|
```
|
|
|
|
### 교훈
|
|
> 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 |
|
|
|
|
---
|
|
|
|
*새 문제-해결 추가 시 해당 카테고리 테이블에 행 추가*
|