File name
Commit message
Commit date
ldu0009 08-12 22f515f refactor: 컴포넌트 스타일을 전역 BEM으로 전환 — 프레임워크 무관 사용 가능 UNIX

컴포넌트 작성 규약#

파일 배치#

컴포넌트 하나당 폴더 하나. 스타일은 여기에 두지 않는다 — @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.*() 토큰으로 지목한다.

@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로 고정한다.

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에 나타난다.