File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
08-14
08-14
08-14
08-14
08-14
08-14
08-14
08-14
// FoxSelectOptionItem — 시안: 통합관리자페이지 디자인시스템(KE9UILWhB8qTBe14uXUn4F) Figma select (컴포넌트 세트 111:272)
//
// 옵션 목록(`fox-select-option`)의 항목 하나다.
//
// 마크업 계약 (React 밖 소비자용):
// <li class="fox-select-option-item" id="sel-opt-0" role="option" aria-selected="true">
// <span class="fox-select-option-item__check">…svg…</span> <!-- 선택됐을 때만, 맨 앞 -->
// <span class="fox-select-option-item__text">…</span>
// <span class="fox-select-option-item__icon">…svg…</span> <!-- 선택, 맨 뒤 -->
// </li>
//
// 위험한 선택지에는 `fox-select-option-item--danger`를 더한다.
//
// 선택 여부는 `aria-selected="true"`가 스타일 훅을 겸한다 — 상태용 클래스를 만들지 않는다.
// 체크 아이콘은 `currentColor`라 선택된 항목의 글자색을 물려받는다. 그 색이 시안의 아이콘
// 색(`#1C589C`)과 같아 별도 색 규칙이 없다.
//
// 시안은 hover·pressed·selected·danger를 모두 `state` 하나로 묶어 놨지만, 앞의 셋은
// 브라우저가 스스로 아는 상태다(`--active`·`:active`·`aria-selected`). 밖에서 지정해야 하는
// 건 danger뿐이라 그것만 클래스로 받는다.
//
// 네이티브 대응이 없어 클래스로 두는 둘:
// - `--active`: 키보드로 이동 중인 항목. 마우스 hover와 같은 모양이어야 하는데 `:hover`로는
// 표현할 수 없다. 리스트박스를 여는 요소의 `aria-activedescendant`가 이 항목을 가리킨다.
// - `--danger`: 위험한 선택지. 값의 성격이라 브라우저도 ARIA도 알 방법이 없다.
//
// `__text`가 남는 폭을 먹어서 체크는 왼쪽 끝, 아이콘은 오른쪽 끝에 붙는다.
//
// 토큰이 아닌 값(FoxButton과 동일한 근거로 승인된 항목):
// - line-height / letter-spacing: 시안 텍스트 스타일의 값이나 Figma가 변수로 export하지 않는다.
// - cursor / flex-shrink: 구조·상호작용 규칙.
@use "@fox/styles/abstracts" as fox;
.fox-select-option-item {
display: flex;
align-items: center;
gap: fox.gap(3);
padding: fox.padding(4) fox.form(padding-sm);
border-radius: fox.form(radius-sm);
background: fox.color(action-secondary);
color: fox.color(font-neutral-default);
font-family: fox.font-family(body);
font-weight: fox.font-weight(regular);
font-size: fox.font-size(body-sm);
// line-height 150% / letter-spacing — 시안 텍스트 스타일 값이나 Figma가 변수로
// export하지 않는다(사용자 승인). 자간은 px이 아니라 em이라 크기·브레이크포인트가
// 바뀌어도 비율이 유지된다.
line-height: 1.5;
letter-spacing: -0.025em;
cursor: pointer;
// 키보드 화살표로 이동한 항목도 마우스 호버와 같은 모양이어야 하므로, 실제 `:hover`
// 대신 JS로 추적하는 active 모디파이어를 쓴다.
&--active {
background: fox.color(action-secondary-hover);
}
&:active {
background: fox.color(action-secondary-pressed);
}
&[aria-selected="true"] {
background: fox.color(action-secondary-selected);
color: fox.color(font-theme-secondary);
}
// danger(위험한 선택지). 배경·눌림은 다른 항목과 같고 글자·아이콘 색만 다르다.
//
// 선택돼도 색을 유지한다 — 위험한 걸 고른 직후가 그 사실을 가장 알려야 할 때다. 다만
// `aria-selected` 규칙과 특이도가 같아 그것만으로는 지지 않으므로, 선택자를 겹쳐 쓴
// 두 번째 줄이 선택된 danger 항목까지 잡는다.
&--danger,
&--danger[aria-selected="true"] {
color: fox.color(font-system-danger);
// 아이콘 계열은 토큰이 따로다 — 라이트 모드에서 글자(danger-60)보다 한 단계
// 밝다(danger-50). 힌트 메시지에서 쓰는 짝과 같다.
.fox-select-option-item__icon,
.fox-select-option-item__check {
color: fox.color(icon-system-danger);
}
}
&__text {
flex: 1;
}
// 시안이 체크 아이콘에 `icon-3`(16px)을 건다. 아이콘 viewBox도 16×16 정사각형이라
// 슬롯을 그대로 채운다.
&__icon,
&__check {
display: inline-flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
inline-size: fox.icon(3);
block-size: fox.icon(3);
}
// 슬롯이 크기를 정하고 안의 SVG는 그 상자를 채운다. 비율이 다른 아이콘이 들어와도
// `preserveAspectRatio` 기본값이 비율을 지키며 축소해 가운데 놓는다.
&__icon > *,
&__check > * {
inline-size: 100%;
block-size: 100%;
}
}