// FoxChip — 시안: 통합관리자페이지 디자인시스템 Figma chip // // 각진 작은 조각이고 **켜짐 여부를 갖는다** — 이것이 `fox-tag`와의 차이다. 태그는 눌러서 // 사라지거나 어디로 넘어가는 조각이라 상태가 남지 않고, 칩은 누른 결과가 자기 자신에게 남는다. // 그래서 알약(`radius: max`)이 아니라 폼 요소와 같은 모서리(`form-radius-*`)를 쓴다. // // 마크업 계약 (React 밖 소비자용): // // //
// // //
// // 켜짐을 `aria-pressed`가 아니라 `--checked` 클래스가 표시한다. 계열마다 켜짐의 출처가 // 달라서다 — check·action은 `aria-pressed`를 들지만 select는 `role="combobox"`라 그 속성을 // 쓸 수 없다(고른 값이 있으면 켜진 것으로 본다). 클래스 하나로 모으면 모양 규칙이 한 벌로 끝난다. // // 상태 규칙은 계열과 무관하게 같다 — 계열이 정하는 것은 아이콘의 유무와 자리뿐이고, 아이콘이 // 앞이냐 뒤냐는 **마크업 순서가 정한다**(`fox-tag`와 같은 방식. `order`나 `row-reverse`를 쓰지 // 않는다). // // ⚠️ hover는 꺼져 있을 때만 걸린다. 시안이 켜짐 위의 hover를 그리지 않았고, 임의로 만들면 // 남색 채움이 눌린 채로 흔들린다. 선택자에 `:not(.fox-chip--checked)`를 박아 못박는다. // // ⚠️ 비활성은 켜짐 여부와 무관하게 한 벌이다(시안 확인 완료 — 비활성+꺼짐 시안이 따로 없다). // 체크 아이콘은 계속 `--checked`가 정하므로 비활성+켜짐이면 흐린 회색 체크가 남는다. // // 크기가 바꾸는 것: 높이·좌우 여백·모서리·글자 크기·아이콘 크기. gap은 두 크기가 같다(`gap-2`). // 아이콘만 크기를 따라가는 점이 `fox-tag`와 다르다 — 태그는 세 크기가 모두 16px이지만 // 시안의 칩은 md 16px(`icon-3`) / lg 20px(`icon-4`)다. // // 토큰이 아닌 값(`fox-button`·`fox-tag`와 동일한 근거로 승인된 항목): // - line-height / letter-spacing: 시안 텍스트 스타일 label/*의 값이나 Figma가 변수로 // export하지 않는다. 두 크기가 모두 `-0.025em`이라 규칙 하나로 끝난다(md는 label/md // 15px→-0.375px, lg는 label/lg 17px→-0.425px — 시안 확인 완료). px이 아니라 em인 이유는 // 글자 크기가 크기 수식어마다, 그리고 브레이크포인트마다 달라지기 때문이다 — px으로 // 박으면 그 자리에서 비율이 어긋난다. // - box-sizing / display / flex / cursor / white-space / aspect-ratio: 구조·상호작용 규칙. // - `--checked`의 `border-color: transparent`: 시안이 켜짐에 테두리를 주지 않는다. 테두리를 // 지우는 대신 투명하게 두는 이유는 배경이 그 자리까지 칠해져 모양은 같으면서, 높이·좌우 // 여백이 계열·상태에 상관없이 한 값으로 유지되기 때문이다. // - `fox-chip-select__list`의 위치·폭: 구조 규칙(아래 주석 참고). @use "@fox/styles/abstracts" as fox; .fox-chip { // 안쪽 여백과 테두리가 바깥 크기를 늘리지 않게 한다 — 고정 높이가 흔들리지 않는다. box-sizing: border-box; display: inline-flex; align-items: center; border: fox.border(1) solid fox.color(border-neutral-default); background: fox.color(action-default); cursor: pointer; color: fox.color(font-neutral-default); font-family: fox.font-family(body); font-weight: fox.font-weight(regular); line-height: 1; letter-spacing: -0.025em; white-space: nowrap; // 글자만 줄어들게 해 아이콘이 밀리지 않게 한다. &__label { min-inline-size: 0; } &__icon { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; // 시안이 아이콘에 정사각 비율을 못박는다. 자리가 좁아 눌려도 글리프가 찌그러지지 않는다. aspect-ratio: 1 / 1; } // 넘긴 SVG가 슬롯을 꽉 채운다 — 크기는 슬롯이 정하고 SVG는 따라온다. &__icon > * { inline-size: 100%; block-size: 100%; } // 화살표만 글자보다 한 단계 흐리다(시안 #6D7882 = font-neutral-disabled-strong). 기본 // 상태에서만이다 — 아래 상태 규칙이 색을 물려주므로 남색 배경 위에서 회색으로 남지 않는다. &__arrow { color: fox.color(font-neutral-disabled-strong); } // ── 크기 ──────────────────────────────────────────────────────────────────── &--lg { block-size: fox.form(height-md); padding-inline: fox.padding(4); gap: fox.gap(2); border-radius: fox.form(radius-md); font-size: fox.font-size(label-lg); } &--lg &__icon { inline-size: fox.icon(4); block-size: fox.icon(4); } &--md { block-size: fox.form(height-sm); padding-inline: fox.padding(3); gap: fox.gap(2); border-radius: fox.form(radius-xsm); font-size: fox.font-size(label-md); } &--md &__icon { inline-size: fox.icon(3); block-size: fox.icon(3); } // ── 상태 ──────────────────────────────────────────────────────────────────── // 순서가 규칙이다: hover → checked → disabled. 뒤에 오는 것이 이긴다. // 꺼져 있을 때만 걸린다(파일 상단 ⚠️ 참고). &:not(&--checked):hover:not(:disabled) { border-color: fox.color(border-theme-secondary); background: fox.color(action-secondary-hover); color: fox.color(font-theme-secondary); } &--checked { // 배경이 테두리 자리까지 칠해져 모양은 테두리 없는 것과 같다(상단 승인 항목 참고). border-color: transparent; background: fox.color(action-secondary-active); color: fox.color(font-neutral-static-inverse); } &:disabled { border-color: fox.color(border-neutral-disabled); background: fox.color(element-neutral-disabled); color: fox.color(font-neutral-disabled-strong); cursor: default; } // 화살표는 기본 상태에서만 흐리고, 상태가 바뀌면 글자 색을 그대로 따라간다. &:not(&--checked):hover:not(:disabled) &__arrow, &--checked &__arrow, &:disabled &__arrow { color: inherit; } } // select 계열을 감싸는 자리. `fox-select-option`이 `position: absolute`라 위치 기준이 되는 // 조상이 필요하다(`fox-select__control`과 같은 역할). // // `inline-block`인 이유는 칩이 글자만큼만 넓어야 하기 때문이다 — 블록이면 줄 전체를 차지해 // 칩 여러 개를 나란히 놓을 수 없다. .fox-chip-select { position: relative; display: inline-block; } // 목록의 폭·위치 규칙은 여기에 없다 — `fox-chip-select-option`이 280px 고정 폭을 스스로 // 갖는다. 예전에는 `fox-select-option`을 빌려 쓰면서 폭을 여기서 덮어썼는데, 전용 목록이 // 생기면서 그 덮어쓰기가 필요 없어졌다.