WYSIWYG: Moveable 가이드라인 고도화(중심/가장자리 스냅, 8px 임계) TDD/구현 및 테스트
Auto PR / open-pr (push) Successful in 18s
Auto Label PR / add-automerge-label (pull_request) Successful in 7s
CI / test (pull_request) Successful in 1m13s

This commit is contained in:
2025-11-16 23:21:43 +09:00
parent ccb706de5b
commit 1b1b916a30
7 changed files with 514 additions and 0 deletions
+38
View File
@@ -1,5 +1,34 @@
# 메인플랜: 랜딩 페이지 빌더
### 가이드라인 고도화 진행(2025-11-16)
- 목표: 객체-객체 스냅 가이드(8px 임계)
- 수직 중심 정렬 가이드/스냅
- 수평 중심 정렬 가이드/스냅
- 좌/우/상/하 가장자리 정렬 가이드/스냅
- TDD
- `components/wysiwyg/Canvas.guidelines.advanced.test.tsx`
- 수직 중심 스냅 가이드(8px) 검증. Moveable 모킹, `act`/`waitFor` 적용
- `components/wysiwyg/Canvas.guidelines.horizontal.test.tsx`
- 수평 중심 스냅 가이드(8px) 검증
- `components/wysiwyg/Canvas.guidelines.edges.test.tsx`
- 좌/우 에지 스냅 가이드(8px) 1차 케이스 검증(T→L 등 에지 페어)
- 구현
- `components/wysiwyg/Canvas.tsx`
- onDrag: 그리드(8px) → 객체 중심 스냅(수직/수평) → 객체 에지 스냅(좌/우/상/하) 우선순위 적용
- 가이드 좌표: 축별로 에지 > 중심 > 그리드 순서로 표시
- 드래그 시작 시 가이드 표시, 종료 시 가이드 해제 유지
- 결과: 전체 테스트 그린(131/131)
#### 오류 원인/디버깅(메모)
- 실패: 수직 중심 스냅 테스트에서 선택 대상이 기본 선택되지 않아 좌표 미변경 → 레이어 objects 순서를 조정(o1을 첫 요소로)
- 실패: 비동기 상태 반영 전 단정 → Moveable 이벤트 호출을 `act`로 감싸고 결과 검증을 `waitFor`/`findByTestId`로 보강하여 해결
- 실패: 가장자리 스냅 미구현으로 208px(그리드) 유지 → 에지 스냅(LL/LR/RL/RR, TT/TB/BT/BB) 페어 계산 로직과 8px 임계 우선순위 적용으로 해결
#### 다음 단계
- 키보드 nudge(Shift/Alt 미세/가속)와 가이드 반영 TDD/구현
- 다중 선택 및 그룹 이동/정렬 스펙 초안 TDD
- 접근성: 키보드 조작 시 라이브 리전 안내/가이드라인 ARIA 노출 정책 검토
## 목표
- 비개발자도 사용 가능한 단일 페이지 랜딩 페이지 빌더.
- 결과물: 정적 ZIP(HTML/CSS/JS) 다운로드. 이미지: 외부 URL 또는 로컬 업로드(서버 저장 없음, ZIP에 패키징). 폰트는 외부 CDN 허용.
@@ -246,6 +275,7 @@
- a11y/SEO/OG/Analytics
## 오류/버그 기록
- [2025-11-16 22:32] jsdom 환경에서 Moveable 내부 `document.elementFromPoint` 미구현으로 예외 발생 → `Canvas.tsx`에 테스트 전용 폴리필 추가(`elementFromPoint: () => null`)로 해결. 린트 any 제거 위해 타입(`DocWithEFP`) 선언 및 미사용 인자 경고 최소화.
- [2025-11-13 22:55] BuilderClientPage 렌더 중 ref 접근 경고 / useRef.current를 렌더 중 참조하여 ESLint 경고 발생 / FormBuilderPanel 통합 시 `useRef(createFormStore())` 사용 / `useMemo(() => createFormStore(), [])`로 스토어 인스턴스 고정하고 `useSyncExternalStore`에 직접 주입하여 해결 / 렌더 중 ref 접근 금지 원칙 재확인
- [2025-11-14 09:35] Vitest 로그에서 i18n 누락 메시지 경고 확인(en: `builder.action.addSelect/addRadio`, `builder.form.actionUrl/honeypot/minSeconds`) → `messages/en.json`에 키 존재 여부 점검 및 누락 보완 후 재실행, 모든 테스트 그린 유지
- [2025-11-14 09:45] 프리뷰 텍스트 매칭 불안정으로 테스트 실패 → `data-testid` 기반 안정화(`preview-seo-title` 등) 및 텍스트 매칭 지점 `Title:``Locale:`로 조정, 전면 그린
@@ -461,6 +491,14 @@
- 정책: 위치 8px 스냅, 회전 15° 스냅(Shift시 1° 미세제어)
- 경계 보정: 0<|deg|<15 구간은 15°/15°로 스냅되도록 조정
- Moveable 통합 완료(TDD→구현→그린)
- 설치: `react-moveable`, `moveable`
- 스모크: Moveable가 드래그/리사이즈/회전 + 8px 스냅 그리드 props로 렌더
- 이벤트 연동: onDrag/onResize/onRotate에서 `snap8`/`snapAngle` 적용, 가이드라인 표시/해제
- Shift 1° 미세 제어 타입가드(`isShiftEvent`) 도입
- target 바인딩: 선택 객체의 data-testid 셀렉터(`[data-testid="obj-<id>"]`)를 Moveable `target`으로 전달
### 다음 작업(캔버스 Moveable 통합)
- 패키지 추가: `react-moveable`, `moveable`
- TDD: Moveable 기반 드래그/리사이즈/회전 일원화 테스트 + 8px/15° 스냅 및 가이드라인 표시/해제 검증