Getting Started
Design Principles
Vapor UI의 컴포넌트 아키텍처와 개발 철학을 이끄는 핵심 디자인 원칙이 문서에서는 Vapor UI의 설계 철학과 6가지 핵심 원칙을 설명합니다. 이 원칙들을 이해하면 컴포넌트를 더 효과적으로 활용할 수 있습니다.
1. Preset 기반의 컴파운드 패턴
Vapor UI는 합성 컴포넌트 패턴을 채택하여 편의성과 유연성을 함께 제공합니다. 빠른 구현이 필요할 때는 Preset 컴포넌트를, 세밀한 제어가 필요할 때는 Primitive 컴포넌트를 사용합니다.
// Preset 패턴 (빠르고 간편)
<Popover.Root>
<Popover.Trigger>Trigger</Popover.Trigger>
<Popover.Popup>Contents</Popover.Popup>
</Popover.Root>
// Primitive 패턴 (완전한 제어)
<Popover.Root>
<Popover.Trigger>Trigger</Popover.Trigger>
<Popover.PortalPrimitive>
<Popover.PositionerPrimitive>
<Popover.PopupPrimitive>Contents</Popover.PopupPrimitive>
</Popover.PositionerPrimitive>
</Popover.PortalPrimitive>
</Popover.Root>이 접근법의 장점은 다음과 같습니다.
- 빠른 시작: Preset 컴포넌트로 즉시 구현할 수 있습니다.
- 세밀한 제어: Primitive 컴포넌트로 커스텀 동작을 구현할 수 있습니다.
- 혼합 사용: 같은 애플리케이션에서 두 패턴을 함께 사용할 수 있습니다.
2. 접근성
Vapor UI는 Base UI를 기반으로 WCAG 2.2 AA를 준수합니다. 키보드 네비게이션과 포커스 표시를 기본으로 지원합니다.
접근성 기능
- Base UI 통합: ARIA 속성, 키보드 내비게이션, 스크린 리더를 자동으로 지원합니다.
- 색상 대비 준수: 자체 개발한 Color Generator가 WCAG AA/AAA 대비 비율을 보장합니다.
- 수학적 디자인 토큰: 일관된 시각적 위계를 위해 수학적 비율로 생성된 토큰을 사용합니다.
// 적절한 ARIA 속성과 키보드 처리가 자동으로 포함됨
<Dialog.Root>
<Dialog.Trigger aria-expanded="true" aria-haspopup="dialog" aria-controls="dialog-popup">
설정 열기
</Dialog.Trigger>
<Dialog.Popup
id="dialog-popup"
aria-label="write dialog title"
aria-description="write dialog description (optional)"
>
{/* 포커스 관리와 ESC 키 처리가 내장됨 */}
</Dialog.Popup>
</Dialog.Root>Color Generator 시스템
Color Generator는 지각적 색상 모델을 사용하여 접근성을 충족하는 색상 팔레트를 생성합니다.
// 색상이 자동으로 대비 요구사항을 충족함
<Badge colorPalette="primary">Primary</Badge>
<Badge colorPalette="success">Success</Badge>
<Badge colorPalette="warning">Warning</Badge>3. 일관된 네이밍 규칙
모든 컴포넌트는 일관된 네이밍 규칙을 따릅니다. 이 규칙을 통해 컴포넌트 사용법을 예측할 수 있습니다.
- 독립 컴포넌트: 단일 이름을 사용합니다.
- 합성 컴포넌트: Dot Notation 표기법을 사용합니다.
// 단일 컴포넌트
<Button>확인</Button>
<Badge>상태</Badge>
// 합성 컴포넌트
<Card.Root>
<Card.Header>
<Text typography="heading3">프로젝트 상태</Text>
</Card.Header>
<Card.Body>
<Text typography="body3">현재 개발 진행상황</Text>
</Card.Body>
<Card.Footer>
<Button>저장</Button>
<Button variant="outline">취소</Button>
</Card.Footer>
</Card.Root>
<Select.Root placeholder="선택">
<Select.Trigger />
<Select.Popup>
<Select.Item value="section1">섹션 1</Select.Item>
<Select.Item value="section2">섹션 2</Select.Item>
<Select.Item value="section3">섹션 3</Select.Item>
</Select.Popup>
</Select.Root>4. 예측 가능한 속성 명명
컴포넌트 속성은 시각적 옵션과 논리적 상태를 기반으로 체계적인 규칙을 따릅니다.
시각적 옵션
// 크기 변형은 일관된 스케일을 따름
<Button size="sm" /> // 작음
<Button size="md" /> // 보통 (기본값)
<Button size="lg" /> // 큼
// 색상 팔레트는 의미론적 명명 사용
<Badge colorPalette="primary" />
<Badge colorPalette="success" />
<Badge colorPalette="danger" />논리적 상태 (동작 기반)
// 상태 속성은 일관된 명명 사용
<Button disabled={!isValid} /> // 비활성화 상태
// 변형명은 의미론적 의도를 반영
<Switch.Root checked /> // 선택 상태
<Switch.Root disabled /> // 비활성 상태
<Switch.Root required /> // 필수 상태
<Switch.Root readOnly /> // 읽기 전용 상태5. TypeScript 통합
모든 컴포넌트는 TypeScript를 완벽하게 지원합니다. 타입 안전성, IntelliSense 자동 완성, 컴파일 타임 오류 검출을 활용할 수 있습니다.
import { Button } from '@vapor-ui/core';
// 완전히 타입화된 컴포넌트 속성
// - colorPalette 자동완성: 'primary' | 'secondary' | 'danger'
// - size 자동완성: 'sm' | 'md' | 'lg'
const CustomButton = ({ colorPalette, size, ...props }: Button.Props) => {
return <Button colorPalette={colorPalette} size={size} {...props} />;
};
// 타입 안전 이벤트 핸들러
<Button
onClick={(event) => console.log(event.target)} // event는 MouseEvent로 적절히 타입화됨
/>;6. Cascade Layer 아키텍처
Vapor UI는 CSS Cascade Layer를 사용하여 스타일 충돌을 방지합니다.
@layer vapor, components;
/* 커스텀 스타일을 안전하게 확장할 수 있음 */
@layer components {
.custom-button {
/* 여기 있는 스타일은 충돌하지 않음 */
}
}