// FoxChipSelectOption — 시안: 통합관리자페이지 디자인시스템 Figma chip-select-option // // 칩의 `select`가 열렸을 때 뜨는 목록이다. `fox-select-option`과 **다른 컴포넌트다** — // 저쪽은 글자 한 줄짜리 listbox고, 이쪽은 시안이 체크박스·라디오 목록이라 이미 있는 // `fox-checkbox-group`·`fox-radio-group`을 그대로 담는다. // // 마크업 계약 (React 밖 소비자용): //
//
//
…
//
// //
// // 폭은 **내용이** 정한다. 시안이 280px을 주지만 고정하지 않는다(사용자 결정) — 항목 글자가 // 길면 잘리고 짧으면 남는데, 어느 쪽도 목록이 스스로 해결할 수 있는 문제가 아니기 때문이다. // 여는 칩의 폭도 따라가지 않는다: 칩은 글자만큼만 좁아서 거기 맞추면 읽을 수 없다 // (`fox-select-option`의 `inset-inline: 0`을 쓰지 않는 이유이기도 하다). // // 폭을 못박아야 하는 자리가 생기면 호출부가 `className`으로 준다. // // ⚠️ 확인 버튼은 **다중 선택 + 모바일**에서만 보인다. 조건이 둘이고 걸리는 자리가 다르다: // // - **다중 선택에만 있다** — React가 정한다. 단일 선택은 하나 고르는 순간 목록이 닫혀서 이 // 버튼이 할 일이 없다(눌러도 아무 일이 없는 버튼이 화면 아래를 차지하게 된다). // - **모바일에만 보인다**(시안 주석 "모바일만 노출") — 이건 CSS가 정한다. 조건부 렌더로 // 하면 창 폭이 바뀔 때마다 DOM이 들락거려서, 열린 채로 화면을 돌리면 포커스가 날아간다. // // 값이 반영되는 시점은 플랫폼과 무관하게 같다(고르는 즉시). 모바일에서 달라지는 것은 닫는 // 수단이 하나 더 생기는 것뿐이고, 데스크톱에서 닫는 것은 바깥 클릭이다. // // ⚠️ `overflow: hidden`이 필요하다. 확인 버튼이 `align-self: stretch`라 판 좌우 끝까지 // 닿는데, 판의 둥근 모서리 밖으로 사각형 배경이 삐져나온다. 버튼에 모서리를 따로 주는 대신 // 판에서 한 번 잘라 낸다(`fox-segmented-control`과 같은 방식). // // 토큰이 아닌 값: // - ⚠️ `max-block-size: 24rem`(240px): 항목이 많을 때의 상한. `fox-select-option`이 같은 // 이유로 잡아 둔 임시값을 그대로 따랐다(그 파일의 TODO 참고). 확정되면 함께 고친다. // - box-sizing / position / display / flex / overflow / z-index / cursor: 구조 규칙. @use "@fox/styles/abstracts" as fox; .fox-chip-select-option { box-sizing: border-box; position: absolute; inset-inline-start: 0; inset-block-start: calc(100% + #{fox.gap(2)}); z-index: 10; display: flex; flex-direction: column; align-items: flex-start; // 내용이 폭을 정한다(파일 상단 주석 참고). `max-content`라 항목 글자가 줄바꿈되지 않고, // 위치 기준인 `.fox-chip-select`가 좁아도 거기 눌리지 않는다. inline-size: max-content; // 확인 버튼의 사각 배경을 둥근 모서리로 잘라 낸다(파일 상단 ⚠️ 참고). overflow: hidden; border: fox.border(1) solid fox.color(border-neutral-subtle); border-radius: fox.radius(3); background: fox.color(surface-neutral-default); // 항목이 놓이는 자리. 판에는 여백을 줄 수 없어(확인 버튼이 끝까지 닿아야 한다) 여기서 준다. &__list { box-sizing: border-box; padding-block: fox.padding(8); padding-inline: fox.padding(9); // 판이 `align-items: flex-start`라 그냥 두면 내용만큼만 넓다. 시안이 이 자리에 // `align-self: stretch`를 준다 — 판 폭이 확인 버튼 때문에 더 넓어져도 여백이 따라간다. align-self: stretch; // ⚠️ 확정 전 임시값 — 파일 상단 승인 목록 참고. max-block-size: 24rem; overflow-y: auto; } // 모바일 전용. 판 좌우 끝까지 닿는다(`align-self: stretch`). &__confirm { box-sizing: border-box; display: flex; justify-content: center; align-items: center; align-self: stretch; flex-shrink: 0; block-size: fox.form(height-lg); padding-inline: fox.form(padding-lg); gap: fox.gap(2); border: none; background: fox.color(button-primary-surface); cursor: pointer; color: fox.color(button-primary-font); font-family: fox.font-family(body); font-size: fox.font-size(label-lg); font-weight: fox.font-weight(medium); line-height: 1; letter-spacing: -0.025em; // 데스크톱에서는 숨긴다(파일 상단 ⚠️ 참고). @include fox.pc { display: none; } } } // 항목 사이 간격만 묶음의 기본값과 다르다 — 체크박스·라디오 묶음의 세로 기본이 `gap-7`(24px) // 인데 이 시안은 `gap-5`(16px)다. 나머지(세로 배치·왼쪽 정렬)는 묶음 것과 같아서 건드리지 // 않는다. 묶음이 `className`을 여는 목적("배치 조정용")에 정확히 해당한다. // // 클래스 둘을 겹쳐 적는다 — 묶음의 `--vertical`과 특정도가 같아, 겹치지 않으면 파일을 // @use 하는 순서가 승부를 가른다. .fox-checkbox-group.fox-chip-select-option__group, .fox-radio-group.fox-chip-select-option__group { gap: fox.gap(5); }