// FoxToggleQuantity — 시안: 통합관리자페이지 디자인시스템 Figma toggle-quantity // // 회색 판 위에 빼기 버튼 · 숫자 · 더하기 버튼이 놓인다. 크기 수식어가 없다 — 시안이 한 벌만 // 준다. // // 마크업 계약 (React 밖 소비자용): //
// // 1 // //
// // 숫자가 `flex: 1 0 0`이라 남는 자리를 혼자 가져간다 — 버튼 둘은 크기가 고정이므로 값이 // 한 자리든 세 자리든 버튼 위치가 흔들리지 않는다. // // ⚠️ 버튼이 `fox-icon-button`이 아니다. `fox-icon-button--sm`과 크기(28)·모서리(4)·아이콘 // 슬롯(20)이 전부 같지만 **배경이 다르다** — 아이콘 버튼의 `default` 계열은 // `button-default-surface`(투명)인데 이 시안은 `action-default`(불투명 흰색)다. 회색 판 // 위에 놓이므로 투명이면 판 색이 그대로 비쳐 버튼이 사라진다. 아이콘 버튼에 흰 배경 계열이 // 생기면 그때 이 규칙을 걷어내고 갈아탄다. // // 비활성은 배경만 바뀐다 — 시안이 disabled에 `border`를 적지 않아 테두리를 지운다(투명으로 // 두어 폭은 남긴다. 지우면 28×28이 26×26이 되어 판 안에서 자리가 밀린다). // // 토큰이 아닌 값: // - ⚠️ `inline-size: 14rem`: **시안의 폭(140px)을 일단 그대로 적용해 둔 것이다.** Figma가 // 변수로 export하지 않았고 토큰 스케일에도 140이 없어서 원시값으로 남아 있다. 토큰이 // 생기면 `fox.*()`로 바꾸고, 폭을 고정하지 않는 쪽으로 정해지면 여기서 뺀다. // 그때까지 폭을 바꿔야 하는 자리는 호출부가 `className`으로 덮는다. // - letter-spacing: 시안 텍스트 스타일 label/lg-em의 값이나 Figma가 변수로 export하지 // 않는다. `-0.025em`이면 17px에서 -0.425px로 시안과 같고, 글자 크기가 브레이크포인트마다 // 달라져도 비율이 유지된다(다른 컴포넌트와 같은 근거). // - 아이콘 색 `fox.primitive(neutral-60)`: 시안 값 `#58616A`를 가진 **semantic 토큰이 없다** // (icon 계열에 있는 것은 neutral-70인 `icon-neutral-default`와 neutral-50인 // `icon-neutral-subtle`뿐이다). 그래서 시안이 가리키는 원시값을 직접 쓴다 — // `fox-select-option`이 그림자 색에 `alpha-black10`을 직접 쓰는 것과 같은 방식이다. // // ⚠️ 원시값이라 **다크 모드에서 뒤집히지 않는다** — 밝은 회색 아이콘이 어두운 버튼 위에 // 그대로 남는다(`action-default`는 다크에서 neutral-100이라 대비는 확보된다). 반전이 // 필요해지면 Figma에서 icon 계열에 neutral-60을 추가한 뒤 그 토큰으로 바꾼다. // - box-sizing / display / flex / cursor / aspect-ratio: 구조·상호작용 규칙. @use "@fox/styles/abstracts" as fox; .fox-toggle-quantity { // 안쪽 여백이 바깥 폭을 늘리지 않게 한다 — 시안의 140px은 테두리까지 포함한 값이다. box-sizing: border-box; display: flex; justify-content: center; align-items: center; // ⚠️ 시안 값을 일단 적용해 둔 상태다 — 파일 상단 주석 참고. inline-size: 14rem; padding: fox.padding(2); gap: fox.gap(2); border-radius: fox.radius(4); background: fox.color(surface-neutral-gray); &__button { box-sizing: border-box; display: flex; flex-shrink: 0; justify-content: center; align-items: center; inline-size: fox.form(height-sm); block-size: fox.form(height-sm); // 시안이 버튼에 정사각 비율을 못박는다. 자리가 좁아 눌려도 모양이 무너지지 않는다. aspect-ratio: 1 / 1; padding: 0; border: fox.border(1) solid fox.color(button-default-border); border-radius: fox.form(radius-sm); background: fox.color(action-default); // 시안 값을 가진 semantic 토큰이 없어 원시값을 직접 쓴다(파일 상단 승인 항목 참고). color: fox.primitive(neutral-60); cursor: pointer; &:disabled { // 테두리를 지우지 않고 투명으로 둔다(파일 상단 주석 참고). border-color: transparent; background: fox.color(button-disabled-surface); cursor: default; } } &__icon { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; inline-size: fox.icon(4); font-size: fox.icon(4); block-size: fox.icon(4); aspect-ratio: 1 / 1; } // 넘긴 SVG가 슬롯을 꽉 채운다 — 크기는 슬롯이 정하고 SVG는 따라온다. &__icon > * { inline-size: 100%; block-size: 100%; } // 남는 자리를 혼자 가져간다 — `flex-basis: 0`이라 글자 길이가 버튼 위치를 밀지 않는다. &__value { flex: 1 0 0; color: fox.color(font-neutral-strong); font-family: fox.font-family(body); font-size: fox.font-size(label-lg); font-weight: fox.font-weight(bold); line-height: 1; letter-spacing: -0.025em; text-align: center; } }