// FoxSortableList — 항목 순서를 끌어서(또는 방향키로) 바꾸는 목록.
//
// 시안에 정렬 목록 컴포넌트가 없어 기획 문구("추가 이미지는 드래그로 순서를 바꾼다",
// BO-MAL-002 ⑤)만으로 만들었다(사용자 확정). 모양은 최소한으로 둔다 — 핸들 하나와
// 끌고 있는 항목·놓을 자리 표시뿐이고, 항목 본문은 호출부가 그린다.
//
// 마크업 계약 (React 밖 소비자용):
//
//
//
//
//
// …항목 본문…
//
//
//
// 토큰이 아닌 값:
// - 끌고 있는 항목의 opacity: 상태 표현이라 색 토큰이 없다. 관례값 0.4.
// - 버튼 초기화(appearance/cursor/색 상속): 구조 규칙.
@use "abstracts" as fox;
.fox-sortable-list {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
gap: fox.gap(4);
padding: 0;
margin: 0;
list-style: none;
&--vertical {
flex-direction: column;
flex-wrap: nowrap;
align-items: stretch;
}
&__item {
position: relative;
display: flex;
align-items: flex-start;
gap: fox.gap(2);
border-radius: fox.radius(3);
// 놓을 자리 테두리가 나타날 때 항목이 밀리지 않도록 투명 테두리를 미리 둔다.
outline: fox.border(2) solid transparent;
outline-offset: fox.number(2);
&--dragging {
opacity: 0.4;
}
&--over {
outline-color: fox.color(border-theme-primary);
}
}
&__handle {
display: inline-flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
padding: fox.padding(1);
margin: 0;
border: 0;
border-radius: fox.radius(2);
background: transparent;
color: fox.color(icon-neutral-subtle);
font-size: fox.icon(3);
cursor: grab;
appearance: none;
&:hover {
background: fox.color(action-default-hover);
color: fox.color(icon-neutral-default);
}
&:active {
cursor: grabbing;
}
}
&__body {
min-inline-size: 0;
flex: 1 1 auto;
}
&--disabled &__item {
outline: 0;
}
}