Figma btn-page(404:5121)의 네 변형을 옮긴다. 자식은 버튼 그룹이고 여럿이면
양끝, 하나면 가운데다.
자식 수를 React에서 세지 않고 CSS `:has(> :only-child)`로 판단한다. 프래그먼트나
조건부 렌더로 자식이 갈려도 실제 DOM이 기준이라 어긋나지 않고, React를 안 쓰는
소비자도 표시할 클래스가 없다.
패널이 자식에게 강제하는 두 가지(사용자 승인):
- 패널 안 그룹 간격은 gap-3(8px). 단독으로 쓰는 그룹의 gap-2(4px)는 그대로다.
- 모바일에서는 패널도 그룹도 세로로 쌓이고 버튼이 폭을 채운다.
시안이 패널 안 버튼에만 주는 min-width 160px은 변수 바인딩이 없고 토큰 스케일에도
160이 없어 리터럴로 둔다(사용자 승인). 상단 80px 여백은 spacing-top-2xlg이며
offset={false}로 끌 수 있다.
Co-Authored-By: Claude Opus 5
새 Figma 파일(KE9UILWhB8qTBe14uXUn4F)의 다섯 시안을 이전 파일과 대조했다.
노드 ID·변형 목록·토큰 값·구조가 전부 같아 스타일 변경분은 없다. 컴파일된
CSS는 바이트 단위로 이전과 동일하다.
btn 컴포넌트 세트 48변형 전체 대조 — 일치
btn-txt 생성 코드가 노드 ID까지 이전 파일과 동일
btn-lnk 생성 코드 바이트 비교 — 동일(에셋 URL만 재발급)
btn-ico 변수 세트·메타데이터 + ghost/overlay/disabled 대표 변형 — 일치
toggle default·ghost·overlay의 active 3종 + 아이콘 fill — 일치
btn-txt의 아이콘 크기는 컴포넌트 세트가 여전히 리터럴이다. 다만 전시 섹션의
인스턴스가 icon/4·3·2를 쓰고 있어 우리 매핑과 의도가 같음을 확인했고 그
근거를 주석에 남긴다.
Co-Authored-By: Claude Opus 5
Figma btn-group(398:4854)에서 가져온 건 간격뿐이다 — 크기·방향과 무관하게
gap-2(4px) 하나여서 그룹에 크기별 스타일이 없다. 배치 규칙(방향·정렬·줄바꿈)은
지시받은 사양이다.
크기는 그룹이 단일 진실 공급원이다. 자식을 cloneElement로 덮어써서 자식이
저마다 다른 size를 줘도 그룹 값으로 통일된다. 세로일 때는 fullWidth까지 함께
내려주고 CSS도 stretch라, React를 안 쓰는 소비자도 같은 결과를 얻는다.
Children.map이 프래그먼트 안으로 들어가지 않아 직접 내려간다. 그러지 않으면
<>…로 감싼 버튼이 덮어쓰기를 피해 가고 Fragment에 size가 붙어 경고가 난다.
호스트 요소(div·span)는 DOM에 없는 속성이 넘어가지 않도록 건드리지 않는다.
Co-Authored-By: Claude Opus 5
Figma 시안(관리자페이지 node 390:439)을 토큰만으로 옮겼다. 컴파일된 CSS의 토큰 참조
50개, 원시 hex/px/rem 리터럴 0개다.
시안에서 확인한 것(추측하지 않음): gap은 lg·md·sm이 gap-2이고 xsm만 gap-1이다.
primary에는 테두리가 없고 secondary·default만 border-1을 갖는다. disabled는 계열과
무관하게 테두리가 사라진다(시안에서 disabled-border 미사용). 높이만 고정이고 좌우
padding만 지정돼 너비는 가변이다.
토큰이 아닌 코드 세 가지를 사용자 승인 후 넣었다.
- line-height: 1 / letter-spacing: -0.025em — 시안 텍스트 스타일 label/*-strong의 값이나
Figma에서 변수로 export되지 않아 토큰이 없다. 네 크기가 같은 값이라 규칙 하나로 끝난다.
- box-sizing: border-box — 높이 고정 + secondary·default의 1px 테두리 때문에 필수다.
없으면 계열별 바깥 높이가 2px 어긋난다.
- cursor·white-space·flex-shrink — 구조·상호작용 규칙. 버튼 스코프에만 적용한다.
모양 규칙은 @fox/styles/_fox-button.scss가 소유하고 module이 @use로 끌어올린다 —
클래스명이 모듈 스코프로 감싸져 전역 충돌이 없고, index.scss는 이 파티셜을 포함하지
않아 CSS가 중복 출력되지 않는다.
아이콘은 계열별 색을 토큰으로 입히기 위해 ReactNode로 받는다(currentColor 전제).
크기는 슬롯이 form-icon-* 토큰으로 정한다.
error 계열은 시안 미정이라 클래스를 비워 뒀다.
Co-Authored-By: Claude Opus 5
토큰 배치 확인과 컴포넌트 예제를 한 페이지에서 본다. 사이드바는 토큰/컴포넌트
두 대분류이며, 토큰 그룹은 CSSOM에서 읽으므로 목록을 코드에 두지 않는다.
컴포넌트는 component-registry의 배열에 항목 하나만 추가하면 사이드바와 본문이
함께 갱신된다 — 만들 때마다 다른 파일을 고칠 필요가 없다.
하니스를 앱이 아니라 @fox에 두는 이유는 폴더를 다른 프로젝트로 복사할 때 함께
따라가게 하기 위함이다. 그래서 앱 상수(테마 저장 키 등)를 import 하지 않고,
테마 전환은 @fox가 소유한 data-theme 계약만 건드린다(저장하지 않는다).
선택 상태는 URL 해시가 SSOT라 새로고침해도 보던 섹션이 유지된다.
같은 목적의 카탈로그를 두 벌 두면 갈라지므로 구 app/design은 함께 제거한다.
Co-Authored-By: Claude Opus 5