# 컴포넌트 작성 규약

## 파일 배치

컴포넌트 하나당 폴더 하나. **스타일은 여기에 두지 않는다** — `@fox/styles/_<name>.scss`가 소유한다.

```
core/components/
  fox-button/
    fox-button.tsx      컴포넌트 (React)
    index.ts            export { FoxButton } from "./fox-button";
  index.ts              배럴 — export * from "./fox-button";

styles/
  _fox-button.scss      모양 규칙 (프레임워크 무관)
  components.scss       전부 묶음 진입점 — 새 컴포넌트를 여기에 @use로 추가
```

**스타일과 컴포넌트를 갈라 둔 이유**는 디자인이 React에 묶이면 안 되기 때문이다. SCSS만
쓰는 프로젝트(Vue·Svelte·서버 템플릿 등)도 `@use "@fox/styles/fox-button"` 하나로 같은
버튼을 얻어야 한다.

## 작성 규칙

**1. 클래스명은 `fox-` 접두사 + BEM.**

```
.fox-button                    블록
.fox-button__label             엘리먼트
.fox-button--primary           모디파이어
```

CSS Modules를 쓰지 않는다. 이름이 전역 유일해서 스코프가 필요 없고, 스코프가 없어야
React 밖에서도 같은 이름으로 쓸 수 있다. **충돌 방지는 접두사 규율이 담당한다.**

**2. 모양 값은 전부 `fox.*()` 토큰으로 지목한다.**

```scss
@use "abstracts" as fox;

.fox-button {
  padding-inline: fox.form(padding-md);
  background: fox.color(button-primary-surface);
  border-radius: fox.form(radius-md);
}
```

원시 값(hex·px·rem 리터럴) 금지. 없는 토큰 이름은 빌드가 실패시킨다. 맞는 토큰이 없으면
쓰지 말고 Figma에 먼저 추가한다 — 토큰 파일은 자동 생성물이다.

토큰으로 표현할 수 없는 값(시안에 있으나 변수화되지 않은 것 등)이 나오면 **사용자와 상의한
뒤** 넣고, 파일 상단 주석에 근거를 남긴다.

**3. 상태는 네이티브 속성으로.**

`disabled`·`aria-busy` 같은 표준 속성을 쓰고 `.is-disabled` 같은 클래스를 만들지 않는다.
SCSS만 쓰는 소비자도 별도 규칙 없이 같은 결과를 얻는다.

**4. 마크업 계약을 스타일 파일 상단에 적는다.**

React 밖 소비자는 그 주석만 보고 DOM을 짜야 한다. 필수 구조와 선택 요소를 예시로 남긴다.

**5. 기본은 Server Component.**

`'use client'`는 상호작용(상태·이벤트 핸들러)이 실제로 필요할 때만 붙인다.

**6. variant는 `Record`로 고정한다.**

```tsx
const TYPE_CLASS: Record<FoxButtonType, string> = {
  primary: "fox-button--primary",
  secondary: "fox-button--secondary",
};
```

계열을 추가하면 맵 누락이 타입 에러가 된다.

**7. `className` prop은 배치용으로만 연다.**

호출부가 넘기는 것은 margin·grid 배치 같은 **위치** 조정이지 디자인 값이 아니다. 모양이
달라져야 하면 모디파이어를 추가한다.

**8. 호스트 앱에 의존하지 않는다.**

`@fox/` 안에서 `@/lib/...` 같은 앱 경로를 import 하지 않는다. 앱이 주는 값은 prop이나
CSS 변수로 받는다.

**9. 만들면 테스트 페이지에 등록한다.**

`@fox/dev-test/component-registry.tsx`의 `COMPONENT_EXAMPLES`에 항목 하나를 추가하면
`/dev-test/design`에 나타난다.
