tfg-design-system
v1.1.1
Published
Platform-agnostic design token library for TFG apps (React Native + Next.js)
Maintainers
Readme
TFG 디자인 시스템
tfg-app(React Native)과tfg-web(Next.js)를 위한 플랫폼 중립적 디자인 토큰 라이브러리입니다.
Figma — TheFair_Design Library에서 추출한 이 패키지는 모든 TFG 플랫폼 전반에 걸쳐 색상, 타이포그래피, 간격, 그림자, 컴포넌트 토큰의 단일 진실 공급원(Single Source of Truth)을 제공합니다.
목차
설치
tfg-app / tfg-web에서 워크스페이스 또는 상대 경로를 통해 이 패키지를 추가합니다:
// package.json (tfg-app 또는 tfg-web 내)
{
"dependencies": {
"tfg-design-system": "file:../tfg-design-system"
}
}이후 실행:
# tfg-design-system 먼저 빌드
cd ../tfg-design-system
npm run build
# 앱에서 설치
npm installArchitecture
src/
├── tokens/ # 플랫폼 중립적 원시 값 (모두 숫자)
│ ├── colors.ts # 16진수 색상 문자열
│ ├── typography.ts # 폰트 스케일 (픽셀 수치)
│ ├── spacing.ts # 4px 기반 간격 스케일
│ ├── radius.ts # 테두리 반지름 스케일
│ ├── shadows.ts # 그림자 원시 값
│ └── index.ts # 모든 토큰 재내보내기
├── platform/ # 플랫폼별 어댑터
│ ├── types.ts # 공유 TypeScript 타입
│ ├── web.ts # CSS 어댑터 (px 문자열, box-shadow)
│ └── native.ts # React Native 어댑터 (fontWeight 문자열, shadow 속성)
├── components/ # 컴포넌트 수준 스타일 토큰
│ └── button.ts # 버튼 / 토글 토큰
└── index.ts # 메인 진입점 (공개 API)설계 원칙
| 항목 | 결정 사항 |
|------|-----------|
| 숫자 타입 | 모든 크기 토큰은 number (px) 형태로 저장. 어댑터가 플랫폼 형식으로 변환. |
| 색상 타입 | 16진수 문자열 — 플랫폼 무관, 변환 불필요. |
| fontWeight | number 형태로 저장 (400, 600…). RN 어댑터가 string으로 변환 ('400', '600'…). |
| lineHeight | 절대 px number로 저장 (예: fontSize × 1.36). RN은 그대로 사용, CSS 어댑터는 '22px'로 변환. |
| letterSpacing | fontSize × -0.025 (Figma −2.5% 관례). 음수 픽셀 값. |
| fontFamily | 플랫폼별 별도: RN은 폰트 파일명, Web은 Pretendard Variable 사용. |
| Shadows | 완전히 다른 구조: RN은 shadowColor/Offset/Opacity/Radius/elevation, CSS는 box-shadow 문자열. |
Token Overview
모든 토큰 파일은 src/tokens/에 위치하며 플랫폼 중립적 — 순수한 숫자와 문자열을 내보냅니다.
| Module | Export | Description |
|------|----------|------|
| colors.ts | colors | 전체 팔레트 + 시맨틱 색상 |
| typography.ts | typography | 폰트 스케일, 굵기, 패밀리 |
| spacing.ts | spacing | 4px 기반 간격 값 |
| radius.ts | radius | 테두리 반지름 값 |
| shadows.ts | shadows | 그림자 원시 값 (색상, 불투명도, 오프셋) |
src/platform/의 플랫폼 어댑터가 이를 바로 사용 가능한 스타일로 변환합니다:
| 내보내기 | 대상 | 설명 |
|----------|------|------|
| webTokens | Next.js / React DOM | typography (px 문자열) + shadows (box-shadow 문자열) |
| nativeTokens | React Native | typography (숫자 + 문자열 fontWeight) + shadows (RN 속성) |
사용법
React Native (tfg-app)
import { nativeTokens, colors, spacing, radius } from 'tfg-design-system'
import { StyleSheet } from 'react-native'
const styles = StyleSheet.create({
// Typography — 텍스트 스타일에 직접 스프레드
heading: {
...nativeTokens.typography.heading,
// → { fontSize: 20, lineHeight: 28, letterSpacing: -0.5,
// fontWeight: '600', fontFamily: 'Pretendard-SemiBold',
// includeFontPadding: false }
color: colors.greyScale.grey_900,
},
body: {
...nativeTokens.typography.body,
// → { fontSize: 16, lineHeight: 21.76, fontWeight: '400', ... }
color: colors.greyScale.grey_700,
},
// Shadows — 컨테이너 스타일에 직접 스프레드
card: {
...nativeTokens.shadows.normal,
// → { shadowColor: 'rgba(0,0,0,0.05)', shadowOffset: {width:0, height:2},
// shadowOpacity: 1, shadowRadius: 8, elevation: 4 }
backgroundColor: colors.background.normal,
borderRadius: radius.md, // 12
padding: spacing[8], // 16
},
// 색상 직접 사용
primaryButton: {
backgroundColor: colors.primary.main, // '#7FFFFF'
borderRadius: radius.sm, // 8
},
})사용 가능한 타이포그래피 변형
| Key | fontSize | fontWeight | lineHeight |
|-----|----------|-----------|-----------|
| display1 | 56 | 400 | 64.4 |
| display2 | 40 | 400 | 48 |
| title1 | 36 | 600 | 45 |
| title2 | 28 | 600 | 36.4 |
| title3 | 24 | 400 | 32.4 |
| heading | 20 | 600 | 28 |
| body | 16 | 400 | 21.76 |
| label | 14 | 400 | 19.32 |
| caption | 12 | 400 | 16.32 |
| tiny | 10 | 400 | 13.6 |
fontWeight토큰으로 다른 굵기 적용:{ ...nativeTokens.typography.body, fontWeight: '600', fontFamily: 'Pretendard-SemiBold' }
Next.js / CSS (tfg-web)
import { webTokens, colors, spacing, radius } from 'tfg-design-system'
import type { CSSProperties } from 'react'
// Typography — React.CSSProperties로 직접 사용
const headingStyle: CSSProperties = {
...webTokens.typography.heading,
// → { fontSize: '20px', lineHeight: '28px', letterSpacing: '-0.5px',
// fontWeight: 600, fontFamily: 'Pretendard Variable, ...' }
color: colors.greyScale.grey_900,
}
// Shadow — CSS box-shadow 값으로 사용
const cardStyle: CSSProperties = {
boxShadow: webTokens.shadows.normal,
// → '0px 2px 8px rgba(0, 0, 0, 0.05)'
backgroundColor: colors.background.normal,
borderRadius: `${radius.md}px`,
padding: `${spacing[8]}px`,
}
// CSS Modules / Tailwind 커스텀 값
export const cssVars = {
'--color-primary': colors.primary.main,
'--shadow-card': webTokens.shadows.normal,
'--font-body': webTokens.typography.body.fontSize,
}사용 가능한 그림자 변형
| 키 | CSS 출력 |
|----|---------|
| normal | 0px 2px 8px rgba(0, 0, 0, 0.05) |
| emphasize | 2px 4px 10px rgba(0, 0, 0, 0.078) |
| strong | 0px 2px 10px rgba(0, 0, 0, 0.239) |
| heavy | 0px 2px 10px rgba(0, 0, 0, 0.322) |
| normalBottom | 0px -4px 4px rgba(0, 0, 0, 0.251) |
플랫폼 차이점
| 속성 | React Native | CSS / Next.js |
|------|-------------|--------------|
| fontSize | number (예: 16) | string (예: '16px') |
| lineHeight | number 절대 px | string (예: '21.76px') |
| fontWeight | string ('600') | number (600) |
| letterSpacing | number px | string px |
| fontFamily | 파일명 ('Pretendard-SemiBold') | CSS명 ('Pretendard Variable') |
| shadow | shadowColor + shadowOffset + shadowOpacity + shadowRadius + elevation | box-shadow: X Y blur rgba(...) |
| includeFontPadding | false (Android 전용) | ❌ 해당 없음 |
핵심: React Native에서
fontWeight는 반드시string('400','600')이어야 하며, number가 아닙니다.nativeTokens가 이를 자동으로 처리합니다.
토큰 레퍼런스
색상
import { colors } from 'tfg-design-system'
colors.primary.main // '#7FFFFF' — 민트 프라이머리
colors.primary.secondary // '#3FE9DC'
colors.greyScale.grey_900 // '#1A1A1A' — 거의 검정색
colors.greyScale.white // '#FFFFFF'
colors.line.normal // '#F7F7F8' — 구분선
colors.line.neutral // '#EDEDF3'
colors.background.normal // '#FFFFFF'
colors.background.highlight // '#F4F8FB' — 파란색조 배경
colors.background.muted // '#CBD6D8' — 은은한 뮤트 배경
// 팔레트
colors.green.green_normal // '#40BA60'
colors.red.red_50 // '#E31D2E'
colors.blue.blue_100 // '#2979FF'타이포그래피
import { typography, fontFamily, fontWeight } from 'tfg-design-system'
// 원시 스케일 값 (모두 숫자)
typography.scale.title1
// → { fontSize: 36, lineHeight: 45, letterSpacing: -0.9, fontWeight: 600 }
// 폰트 굵기 (숫자)
fontWeight.regular // 400
fontWeight.medium // 500
fontWeight.semibold // 600
fontWeight.bold // 700
// 폰트 패밀리
fontFamily.native.semibold // 'Pretendard-SemiBold'
fontFamily.web.fallback // 'Pretendard Variable, Pretendard, ...'그림자
import { shadows } from 'tfg-design-system'
// 원시 값 (플랫폼 중립적)
shadows.normal
// → { color: '#000000', opacity: 0.05, offsetX: 0, offsetY: 2, blurRadius: 8, ... }
// 플랫폼 어댑터로 스타일 출력:
import { webTokens, nativeTokens } from 'tfg-design-system'
webTokens.shadows.normal // '0px 2px 8px rgba(0, 0, 0, 0.05)'
nativeTokens.shadows.normal // { shadowColor: 'rgba(0,0,0,0.05)', shadowOffset: {width:0, height:2}, ... }Spacing
import { spacing } from 'tfg-design-system'
spacing[0] // 0
spacing[4] // 8 (인덱스 × 2, 4px 기반)
spacing[8] // 16 ← 기본 페이지 패딩
spacing[12] // 24
spacing[16] // 32
// React Native: paddingHorizontal: spacing[8] → 16
// CSS/Next.js: padding: `${spacing[8]}px` → '16px'Border Radius
import { radius } from 'tfg-design-system'
radius.none // 0
radius.xs // 4
radius.sm // 8 ← 버튼 기본값
radius.md // 12 ← 카드 기본값
radius.lg // 16
radius.xl // 24
radius.full // 999 — 알약 / 원형Component Tokens — Button
import { buttonTokens } from 'tfg-design-system'
// Sizes
buttonTokens.size.lg.height // 56
buttonTokens.size.lg.paddingHorizontal // 16
buttonTokens.size.lg.borderRadius // 8
buttonTokens.size.lg.fontWeight // 600
// Variants
buttonTokens.variant.contained.primary.backgroundColor // '#7FFFFF'
buttonTokens.variant.contained.primary.textColor // '#000000'
buttonTokens.variant.outlined.primary.borderColor // '#EDEDF3'
buttonTokens.variant.outlined.primary.borderWidth // 1
// Toggle
buttonTokens.toggle.track.width // 51
buttonTokens.toggle.track.active.backgroundColor // '#7FFFFF'
buttonTokens.toggle.thumb.size // 27빌드
# 의존성 설치
npm install
# 빌드 (lib/ 디렉토리에 출력)
npm run build
# 감시 모드 빌드 (개발 중)
npm run build:watch빌드 결과물은 lib/에 위치합니다:
lib/index.js— CommonJS 진입점lib/index.d.ts— TypeScript 선언 파일lib/index.d.ts.map— 선언 소스맵 (IDE go-to-source용)
파일 구조
tfg-design-system/
├── src/
│ ├── tokens/
│ │ ├── colors.ts ← 모든 색상 (Figma 시맨틱 + 전체 팔레트)
│ │ ├── typography.ts ← 폰트 스케일, 굵기, 패밀리
│ │ ├── spacing.ts ← 4px 기반 간격
│ │ ├── radius.ts ← 테두리 반지름 값
│ │ ├── shadows.ts ← 그림자 원시 값 (Figma 출처)
│ │ └── index.ts ← tokens/ 배럴 내보내기
│ ├── platform/
│ │ ├── types.ts ← 공유 TS 타입 (NativeTextStyle 등)
│ │ ├── web.ts ← CSS 어댑터 (toPx, toBoxShadow, webTokens)
│ │ └── native.ts ← RN 어댑터 (toNativeFontWeight, nativeTokens)
│ ├── components/
│ │ └── button.ts ← 버튼/토글 컴포넌트 토큰
│ └── index.ts ← 공개 API — 여기서 import
├── lib/ ← 빌드 결과물 (자동 생성, 직접 수정 금지)
├── package.json
├── tsconfig.json
└── README.mdFigma 출처
토큰 값은 Figma → TheFair_Design Library에서 추출됩니다:
| Figma 페이지 | 토큰 카테고리 |
|-------------|-------------|
| 색상 - Semantic | colors.primary, colors.line, colors.background |
| 색상 - Semantic (Elevation) | shadows.* |
| 색상 - Semantic (Variable defs) | typography.scale.* |
| tfg-app 코드베이스 | colors.palette (green, red, blue 등) |
letterSpacing 공식:
fontSize × -0.025(Figma: fontSize의 −2.5%)
