// FoxButton 스타일 — 시안: 관리자페이지 Figma, node 390:439 (`btn`) // // **모든 디자인 값은 토큰으로만 지목한다.** 시안의 Figma 변수가 우리 토큰과 1:1로 // 대응하므로 예외가 필요 없었고, 아래 세 가지만 토큰이 아니다(사용자 승인 후 사용): // // 1. `line-height: 1` / `letter-spacing: -0.025em` // 시안 텍스트 스타일 `label/*-strong`의 값이다(lineHeight 1, letterSpacing -2.5%). // Figma에서 텍스트 스타일로만 존재하고 변수로 export되지 않아 토큰이 없다. // 네 크기가 모두 같은 값이라 스케일이 아니고 규칙 하나로 끝난다. // 2. `box-sizing: border-box` // 높이가 고정인데 secondary·default가 1px 테두리를 가져, 없으면 계열별로 바깥 // 높이가 2px 어긋난다. 디자인 값이 아니라 레이아웃 메커니즘이다. // 3. `cursor` / `white-space` / `flex-shrink` 등 구조·상호작용 규칙. // // 이 파일은 CSS를 출력하므로 `fox-button.module.scss` **한 곳에서만** `@use`한다. // 전역 진입점(`index.scss`)에 넣으면 안 된다. @use "abstracts" as fox; .button { box-sizing: border-box; display: inline-flex; align-items: center; justify-content: center; border: none; cursor: pointer; // 시안 label/*-strong. 크기별 font-size는 아래 size 클래스가 정한다. font-family: fox.font-family(body); font-weight: fox.font-weight(medium); line-height: 1; letter-spacing: -0.025em; white-space: nowrap; } .button:disabled { cursor: default; } .fullWidth { inline-size: 100%; } // 라벨이 길어도 아이콘을 밀어내지 않게 라벨만 줄어들 수 있게 둔다. .label { min-inline-size: 0; } // 아이콘 슬롯. 크기는 size 클래스가, 색은 type 클래스가 정한다 — // 안에 들어오는 SVG는 `currentColor`로 그려야 계열별 색이 적용된다. .icon, .spinner { display: inline-flex; flex-shrink: 0; align-items: center; justify-content: center; } .icon > * { inline-size: 100%; block-size: 100%; } // ── 크기 ──────────────────────────────────────────────────────────────────── // 높이만 고정이고 너비는 내용에 따라 가변이다(시안도 좌우 padding만 지정). .sizeLg { block-size: fox.form(height-lg); padding-inline: fox.form(padding-lg); border-radius: fox.form(radius-lg); gap: fox.gap(2); font-size: fox.font-size(label-lg); .icon, .spinner { inline-size: fox.form(icon-lg); block-size: fox.form(icon-lg); } } .sizeMd { block-size: fox.form(height-md); padding-inline: fox.form(padding-md); border-radius: fox.form(radius-md); gap: fox.gap(2); font-size: fox.font-size(label-md); .icon, .spinner { inline-size: fox.form(icon-md); block-size: fox.form(icon-md); } } .sizeSm { block-size: fox.form(height-sm); padding-inline: fox.form(padding-sm); border-radius: fox.form(radius-sm); gap: fox.gap(2); font-size: fox.font-size(label-sm); .icon, .spinner { inline-size: fox.form(icon-sm); block-size: fox.form(icon-sm); } } // xsm만 gap이 한 단계 좁다(시안 확인). .sizeXsm { block-size: fox.form(height-xsm); padding-inline: fox.form(padding-xsm); border-radius: fox.form(radius-xsm); gap: fox.gap(1); font-size: fox.font-size(label-xsm); .icon, .spinner { inline-size: fox.form(icon-xsm); block-size: fox.form(icon-xsm); } } // ── 계열 ──────────────────────────────────────────────────────────────────── // 아이콘 색은 라벨 색과 별개 토큰으로 지정돼 있어(시안) 각각 지목한다 — // 지금은 두 값이 같지만 토큰이 갈라지면 시안을 따라가야 한다. .typePrimary { background: fox.color(button-primary-surface); color: fox.color(button-primary-font); .icon { color: fox.color(icon-neutral-static-inverse); } &:hover:not(:disabled) { background: fox.color(button-primary-surface-hover); } &:active:not(:disabled) { background: fox.color(button-primary-surface-pressed); } } .typeSecondary { border: fox.border(1) solid fox.color(button-secondary-border); background: fox.color(button-secondary-surface); color: fox.color(button-secondary-font); .icon { color: fox.color(icon-theme-primary-strong); } &:hover:not(:disabled) { background: fox.color(button-secondary-surface-hover); } &:active:not(:disabled) { background: fox.color(button-secondary-surface-pressed); } } .typeDefault { border: fox.border(1) solid fox.color(button-default-border); background: fox.color(button-default-surface); color: fox.color(button-default-font); .icon { color: fox.color(icon-neutral-default); } &:hover:not(:disabled) { background: fox.color(button-default-surface-hover); } &:active:not(:disabled) { background: fox.color(button-default-surface-pressed); } } // ⚠️ error 계열은 시안 미정이라 규칙을 두지 않는다. 확정되면 여기에 채운다. .typeError { } // ── 비활성 ────────────────────────────────────────────────────────────────── // 계열과 무관하게 같은 모양이고 **테두리가 없다**(시안에서 disabled-border 미사용). // `.button:disabled`가 계열 클래스보다 특이도가 높아 뒤에 두지 않아도 이긴다. .button:disabled { border: none; background: fox.color(button-disabled-surface); color: fox.color(button-disabled-font); .icon { color: fox.color(icon-neutral-disabled-strong); } }