feat(cupang): 드래그 조작감 개선 — 핸들·플레이스홀더·오토스크롤
Pointer Events 기반으로 바꾸고(터치·펜 지원, setPointerCapture 로 창 밖 이동에도 이벤트 유실 없음) 업무툴 수준의 조작 피드백을 붙였다. - 드래그 핸들(⠿)에서만 드래그 시작 → 카드 클릭/텍스트 선택과 충돌 없음 - 커서를 따라오는 고스트에 "잔여 N박스" 배지, 담을 수 없는 위치에서는 빨간 테두리로 금지 표시 - 대상 센터에 "○○ — 여기에 담기" 플레이스홀더를 끼워 놓일 자리를 보여줌 - 센터 목록 위/아래 44px 안에 커서가 오면 자동 스크롤(센터가 많을 때 필수) - pointermove 처리는 requestAnimationFrame 으로 1프레임 1회만 실행 - pointercancel / 창 blur / Esc 에서 드래그를 안전하게 취소 SortableJS 도입은 보류했다. 웨일에서 네이티브 DnD 가 시작조차 되지 않아 어차피 fallback 모드로만 동작하고, 브라우저 실측 검증 수단이 없는 상태에서 의존성만 늘어난다. tests/js: 핸들 밖 드래그 차단·고스트 배지·플레이스홀더·금지 표시·Esc 취소 시나리오 추가(rAF 지연을 고려해 프레임 대기). 전체 통과. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+49
-1
@@ -596,7 +596,7 @@
|
||||
}
|
||||
|
||||
/* ② 요약: 카드가 드래그 가능함을 알린다 */
|
||||
.cpg-sum-prod.is-draggable, .cpg-box-card.is-draggable { cursor: grab; }
|
||||
.cpg-sum-prod.is-draggable, .cpg-box-card.is-draggable { cursor: pointer; }
|
||||
.cpg-sum-prod.is-draggable:hover, .cpg-box-card.is-draggable:hover {
|
||||
border-color: var(--color-rich-black);
|
||||
}
|
||||
@@ -695,3 +695,51 @@ body.cpg-dragging { cursor: grabbing; user-select: none; }
|
||||
/* 드래그 중일 때 ③ 영역을 강조 — 어디에 놓아야 하는지 보이게 */
|
||||
.cpg-dist-card.is-drop-ready { outline: 2px dashed var(--color-rich-black); outline-offset: 2px; }
|
||||
.cpg-dist-card.is-drop-ready .cpg-dist-center { border-color: var(--color-midtone-gray); }
|
||||
|
||||
/* 드래그 핸들 / 플레이스홀더 / 고스트 배지 */
|
||||
.cpg-drag-handle {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 4px;
|
||||
border-radius: 5px;
|
||||
color: var(--color-midtone-gray);
|
||||
cursor: grab;
|
||||
touch-action: none; /* 모바일에서 스크롤 제스처와 충돌 방지 */
|
||||
user-select: none;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
.cpg-drag-handle:hover { background: var(--color-ghost-gray); color: var(--color-rich-black); }
|
||||
body.cpg-dragging .cpg-drag-handle { cursor: grabbing; }
|
||||
|
||||
.cpg-drop-placeholder {
|
||||
margin-top: 6px;
|
||||
padding: 8px;
|
||||
border: 1.5px dashed var(--color-rich-black);
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
color: var(--color-rich-black);
|
||||
background: var(--color-ghost-gray);
|
||||
animation: cpg-ph-in .15s ease-out;
|
||||
}
|
||||
@keyframes cpg-ph-in {
|
||||
from { opacity: 0; transform: translateY(-4px); }
|
||||
to { opacity: 1; transform: none; }
|
||||
}
|
||||
|
||||
.cpg-drag-badge {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
background: var(--color-rich-black);
|
||||
color: var(--color-canvas-white);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.cpg-drag-ghost.is-invalid { border-color: var(--color-callout-red); }
|
||||
.cpg-drag-ghost.is-invalid .cpg-drag-badge { background: var(--color-callout-red); }
|
||||
|
||||
Reference in New Issue
Block a user