Figma textarea(135:1655)의 6상태를 옮긴다. 시안에 크기 축이 없어 상자는
하나뿐이고 높이는 rows가 정한다(기본 5줄, 시안과 같음).
상태 판정은 FoxInput과 같은 두 갈래다 — 기본은 브라우저가 판단하고(포커스·
값·네이티브 속성·aria-invalid), data-state를 주면 그 모양으로 고정된다.
상태 매트릭스도 FoxInput과 동일해 규칙을 그대로 옮겼다.
하단은 왼쪽 헬퍼와 오른쪽 글자수 카운터로 나뉜다. 카운터는 현재 길이만 굵고
색이 다르며, 오류일 때 빨개진다(시안의 error 변형이 100/100을 빨갛게 둔다).
maxLength가 없으면 개수만 적는다. 비제어 입력의 길이는 직접 따라간다.
리사이즈는 시안에 신호가 없어 폭이 흔들리지 않게 세로만 허용한다.
Co-Authored-By: Claude Opus 5
Figma input(135:621)의 2타입 × 3크기 × 6상태를 옮긴다. 네이티브 을
감싸므로 시안에 없는 password·email·number 등 모든 타입이 그대로 통한다.
상태는 두 갈래다. 기본은 브라우저가 판단한다 — 포커스는 :focus-within,
비활성·읽기전용은 네이티브 속성, 오류는 aria-invalid. 시안의 completed는
default와 글자색만 다른데 그건 플레이스홀더와 입력값의 네이티브 차이라 규칙이
필요 없다. 모양을 못박아야 하면 루트에 data-state를 준다.
date는 브라우저가 그리는 달력 아이콘과 피커를 그대로 쓴다(사용자 승인).
지우기 버튼은 포커스 중이고 값이 있을 때만 뜨고 누르면 값을 비운다 —
비제어 입력은 DOM을 직접 비우고 제어 입력은 onChange()로 알린다.
헬퍼 메시지 색은 상태를 따라간다(기본 회색 · 포커스 파랑 · 완료 초록 ·
오류 빨강). 아이콘은 @fox에 아이콘 세트가 없어 슬롯으로 두었다.
Co-Authored-By: Claude Opus 5
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 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