Skip to Content

Button

사용자 액션을 트리거하는 버튼 컴포넌트입니다.

개요

Button은 가장 기본적인 인터랙티브 요소로, 클릭 이벤트를 처리하고 사용자 액션을 실행합니다. Cals Button은 Cals 브랜드 컬러(Pink, Blue, Purple)와 예약 상태 컬러 5가지가 적용되어 있으며, Foundation Button의 모든 기능을 상속합니다.

주요 특징:

  • 6가지 기본 Variant + 5가지 예약 상태 Variant
  • 3가지 Size (sm, md, lg)
  • Cals 브랜드 컬러 적용 (Pink #e91e63, Blue #03a9f4, Purple #9c27b0)
  • 예약 상태 컬러 완벽 지원 (Available, Pending, Confirmed, Cancelled, Completed)
  • Loading 상태 지원
  • Icon 지원
  • 완벽한 접근성 (WCAG 2.1 AA)

사용 사례:

  • Cals 예약 시스템 액션 버튼 (예약하기, 승인하기, 취소하기)
  • 예약 상태 변경 버튼
  • 예약 관리 대시보드 액션
  • 고객 예약 확정/취소 버튼

설치

npx @vortex/cli add button --package cals

기본 사용법

import "@vortex/ui-cals/theme"; // Cals 테마 적용 import { Button } from "@vortex/ui-cals"; export default function Example() { return <Button>Click me</Button>; }

Variants (변형)

Primary (Cals Pink)

기본 액션에 사용하는 Cals Pink 버튼입니다.

<Button variant="primary">예약하기</Button>

Secondary (Cals Blue)

보조 액션에 사용하는 Cals Blue 버튼입니다.

<Button variant="secondary">예약 상세보기</Button>

Accent (Cals Purple)

특별한 상태나 강조가 필요한 액션에 사용하는 Cals Purple 버튼입니다.

<Button variant="accent">VIP 예약</Button>

Outline

아웃라인 스타일의 버튼입니다.

<Button variant="outline">취소</Button>

Ghost

배경 없이 텍스트만 표시되는 버튼입니다.

<Button variant="ghost">이전으로</Button>

링크 스타일의 버튼입니다.

<Button variant="link">예약 규정 보기</Button>

Destructive

삭제와 같은 위험한 액션에 사용하는 버튼입니다.

<Button variant="destructive">예약 영구 삭제</Button>

예약 상태 Variants ⭐

Available (예약 가능)

예약 가능한 상태를 나타내는 Green 버튼입니다.

<Button variant="available">지금 예약하기</Button>

사용 예시:

  • 예약 가능한 시간대 선택 버튼
  • 예약 가능 상태로 변경
  • 신규 예약 등록

Pending (승인 대기)

승인 대기 상태를 나타내는 Orange 버튼입니다.

<Button variant="pending">승인 대기중</Button>

사용 예시:

  • 관리자 승인 대기 표시
  • 대기 목록 등록
  • 승인 요청 버튼

Confirmed (예약 확정)

예약 확정 상태를 나타내는 Blue 버튼입니다.

<Button variant="confirmed">예약 확정됨</Button>

사용 예시:

  • 확정된 예약 표시
  • 예약 확정 처리 버튼
  • 예약 확인서 발급

Cancelled (예약 취소)

예약 취소 상태를 나타내는 Red 버튼입니다.

<Button variant="cancelled">예약 취소</Button>

사용 예시:

  • 예약 취소 처리 버튼
  • 취소된 예약 표시
  • 환불 처리

Completed (서비스 완료)

서비스 완료 상태를 나타내는 Purple 버튼입니다.

<Button variant="completed">서비스 완료</Button>

사용 예시:

  • 완료된 예약 표시
  • 서비스 완료 처리 버튼
  • 리뷰 작성 유도

Sizes (크기)

Small

<Button size="sm">Small Button</Button>

Medium (기본)

<Button size="md">Medium Button</Button>

Large

<Button size="lg">Large Button</Button>

States (상태)

Disabled

<Button disabled>Disabled Button</Button>

Loading

<Button loading>Loading...</Button>

Icon 사용

Icon + Text

import { Calendar, Check, X, Clock } from 'lucide-react' <Button variant="available"> <Calendar size={16} className="mr-xs" /> 예약하기 </Button> <Button variant="confirmed"> <Check size={16} className="mr-xs" /> 예약 확정 </Button> <Button variant="cancelled"> <X size={16} className="mr-xs" /> 예약 취소 </Button> <Button variant="pending"> <Clock size={16} className="mr-xs" /> 승인 대기 </Button>

Icon Only

import { RefreshCw } from "lucide-react"; <Button size="sm" aria-label="예약 새로고침"> <RefreshCw size={16} /> </Button>;

Cals 브랜딩

브랜드 컬러

Cals Button은 다음 브랜드 컬러를 사용합니다:

  • Primary (Pink): #e91e63 - 주요 액션, CTA 버튼 (예약하기)
  • Secondary (Blue): #03a9f4 - 보조 액션 (상세보기)
  • Accent (Purple): #9c27b0 - 특별한 상태 (VIP 예약)

예약 상태 컬러 ⭐

Cals는 예약 시스템에 특화된 5가지 상태 컬러를 제공합니다:

  • Available (Green): #4caf50 - 예약 가능
  • Pending (Orange): #ff9800 - 승인 대기
  • Confirmed (Blue): #03a9f4 - 예약 확정
  • Cancelled (Red): #f44336 - 예약 취소
  • Completed (Purple): #9c27b0 - 서비스 완료

Cals 특화 사용 가이드

예약 관리 시스템 액션:

// 신규 예약 등록 - Primary (Cals Pink) <Button variant="primary">예약하기</Button> // 예약 가능 상태 - Available (Green) <Button variant="available">지금 예약 가능</Button> // 승인 대기 - Pending (Orange) <Button variant="pending">승인 요청</Button> // 예약 확정 - Confirmed (Blue) <Button variant="confirmed">예약 확정</Button> // 예약 취소 - Cancelled (Red) <Button variant="cancelled">예약 취소</Button> // 서비스 완료 - Completed (Purple) <Button variant="completed">서비스 완료</Button>

예약 상태 변경 워크플로우:

<div className="flex gap-md"> <Button variant="outline">이전으로</Button> <Button variant="confirmed">예약 확정하기</Button> </div>

예약 목록 액션 버튼:

import { Calendar, Check, X, Clock } from "lucide-react"; <div className="flex gap-sm"> <Button variant="available"> <Calendar size={16} className="mr-xs" /> 신규 예약 </Button> <Button variant="pending"> <Clock size={16} className="mr-xs" /> 승인 대기 목록 </Button> <Button variant="confirmed"> <Check size={16} className="mr-xs" /> 확정된 예약 </Button> <Button variant="cancelled"> <X size={16} className="mr-xs" /> 취소된 예약 </Button> </div>;

Foundation/iCignal/Cals 비교

속성FoundationiCignalCals
Primary Color#3B82F6 (중립 블루)#2196f3 (iCignal 블루)#e91e63 (Cals 핑크)
브랜드 적용없음iCignal AnalyticsCals 예약 시스템
특화 Variants없음없음5가지 예약 상태
사용 맥락범용데이터 분석예약 관리
예약 상태 지원✅ Available/Pending/Confirmed/Cancelled/Completed
커스터마이징자유롭게 가능브랜드 가이드 준수브랜드 가이드 + 예약 컨텍스트 준수
테마중립적 테마iCignal 테마Cals 테마 (@vortex/ui-cals/theme)

import 경로 차이:

// Foundation import { Button } from "@vortex/ui-foundation"; // iCignal import "@vortex/ui-icignal/theme"; import { Button } from "@vortex/ui-icignal"; // Cals import "@vortex/ui-cals/theme"; // 테마 import 필수 import { Button } from "@vortex/ui-cals";

Props API

PropTypeDefaultDescription
variant’primary’ | ‘secondary’ | ‘accent’ | ‘outline’ | ‘ghost’ | ‘link’ | ‘destructive’ | ‘available’ | ‘pending’ | ‘confirmed’ | ‘cancelled’ | ‘completed''primary’버튼 변형
size’sm’ | ‘md’ | ‘lg''md’버튼 크기
disabledbooleanfalse비활성화 상태
loadingbooleanfalse로딩 상태
onClick() => void-클릭 이벤트 핸들러
type’button’ | ‘submit’ | ‘reset''button’버튼 타입
classNamestring-추가 CSS 클래스
childrenReactNode-버튼 내용

접근성

Button 컴포넌트는 WCAG 2.1 AA 기준을 준수합니다.

ARIA 속성:

  • role="button" (자동 적용)
  • aria-disabled="true" (disabled 상태일 때)
  • aria-label (Icon Only 버튼에 필수)

키보드 네비게이션:

  • Enter / Space: 버튼 클릭
  • Tab: 다음 요소로 포커스 이동
  • Shift + Tab: 이전 요소로 포커스 이동

스크린 리더 지원:

  • 버튼 텍스트가 명확하게 읽힘
  • Loading 상태 안내
  • Disabled 상태 안내

색상 대비 (Cals 브랜드 컬러 기준):

  • Primary (Pink): 4.5:1 이상
  • Secondary (Blue): 4.5:1 이상
  • Accent (Purple): 4.5:1 이상
  • Available (Green): 4.5:1 이상
  • Pending (Orange): 4.5:1 이상
  • Confirmed (Blue): 4.5:1 이상
  • Cancelled (Red): 4.5:1 이상
  • Completed (Purple): 4.5:1 이상

예제

예제 1: 예약 관리 대시보드 ⭐

import "@vortex/ui-cals/theme"; import { Button } from "@vortex/ui-cals"; import { Calendar, Check, X, Clock, CheckCircle } from "lucide-react"; export default function ReservationDashboard() { return ( <div className="space-y-lg"> <h2>예약 관리 대시보드</h2> {/* 예약 상태별 액션 버튼 */} <div className="grid grid-cols-5 gap-md"> <Button variant="available" size="lg" className="flex-col py-lg"> <Calendar size={24} className="mb-sm" /> <span className="text-sm">예약 가능</span> <span className="text-2xl font-bold mt-xs">12</span> </Button> <Button variant="pending" size="lg" className="flex-col py-lg"> <Clock size={24} className="mb-sm" /> <span className="text-sm">승인 대기</span> <span className="text-2xl font-bold mt-xs">5</span> </Button> <Button variant="confirmed" size="lg" className="flex-col py-lg"> <Check size={24} className="mb-sm" /> <span className="text-sm">예약 확정</span> <span className="text-2xl font-bold mt-xs">28</span> </Button> <Button variant="cancelled" size="lg" className="flex-col py-lg"> <X size={24} className="mb-sm" /> <span className="text-sm">예약 취소</span> <span className="text-2xl font-bold mt-xs">3</span> </Button> <Button variant="completed" size="lg" className="flex-col py-lg"> <CheckCircle size={24} className="mb-sm" /> <span className="text-sm">서비스 완료</span> <span className="text-2xl font-bold mt-xs">45</span> </Button> </div> {/* 신규 예약 버튼 */} <Button variant="primary" size="lg" className="w-full"> <Calendar size={20} className="mr-sm" /> 신규 예약 등록 </Button> </div> ); }

예제 2: 예약 상태 변경 워크플로우 ⭐

import "@vortex/ui-cals/theme"; import { Button } from "@vortex/ui-cals"; import { Check, X, Clock } from "lucide-react"; export default function ReservationStatusChange() { const [status, setStatus] = useState("pending"); const [loading, setLoading] = useState(false); const handleConfirm = async () => { setLoading(true); await confirmReservation(); setStatus("confirmed"); setLoading(false); }; const handleCancel = async () => { setLoading(true); await cancelReservation(); setStatus("cancelled"); setLoading(false); }; return ( <Card> <CardHeader> <h3>예약 #12345</h3> {status === "pending" && ( <Badge variant="pending"> <Clock size={14} className="mr-xs" /> 승인 대기중 </Badge> )} {status === "confirmed" && ( <Badge variant="confirmed"> <Check size={14} className="mr-xs" /> 예약 확정됨 </Badge> )} {status === "cancelled" && ( <Badge variant="cancelled"> <X size={14} className="mr-xs" /> 예약 취소됨 </Badge> )} </CardHeader> <CardContent> <div className="space-y-sm"> <p> <strong>고객명:</strong> 홍길동 </p> <p> <strong>예약일시:</strong> 2024-01-20 14:00 </p> <p> <strong>서비스:</strong> 프리미엄 패키지 </p> </div> </CardContent> <CardFooter className="flex gap-md justify-end"> {status === "pending" && ( <> <Button variant="cancelled" loading={loading} onClick={handleCancel} > <X size={16} className="mr-xs" /> 예약 거절 </Button> <Button variant="confirmed" loading={loading} onClick={handleConfirm} > <Check size={16} className="mr-xs" /> 예약 확정 </Button> </> )} {status === "confirmed" && ( <Button variant="completed"> <CheckCircle size={16} className="mr-xs" /> 서비스 완료 처리 </Button> )} </CardFooter> </Card> ); }

예제 3: 예약 가능 시간대 선택 ⭐

import "@vortex/ui-cals/theme"; import { Button } from "@vortex/ui-cals"; import { Calendar, Users } from "lucide-react"; export default function TimeSlotSelection() { const [selectedTime, setSelectedTime] = useState(null); const timeSlots = [ { time: "10:00", status: "available", seats: 5 }, { time: "11:00", status: "available", seats: 3 }, { time: "12:00", status: "pending", seats: 2 }, { time: "13:00", status: "confirmed", seats: 0 }, { time: "14:00", status: "available", seats: 8 }, { time: "15:00", status: "completed", seats: 0 }, ]; return ( <div className="space-y-lg"> <div className="flex items-center gap-md"> <Calendar size={24} /> <h3>2024년 1월 20일 (토) 예약 가능 시간</h3> </div> <div className="grid grid-cols-3 gap-md"> {timeSlots.map((slot) => ( <Button key={slot.time} variant={slot.status} size="lg" disabled={slot.status !== "available"} onClick={() => setSelectedTime(slot.time)} className="flex-col py-lg" > <span className="text-xl font-bold">{slot.time}</span> {slot.status === "available" && ( <span className="text-sm mt-xs flex items-center"> <Users size={14} className="mr-xs" /> {slot.seats}석 남음 </span> )} {slot.status === "pending" && ( <span className="text-xs mt-xs">승인 대기</span> )} {slot.status === "confirmed" && ( <span className="text-xs mt-xs">예약 마감</span> )} {slot.status === "completed" && ( <span className="text-xs mt-xs">완료됨</span> )} </Button> ))} </div> {selectedTime && ( <Button variant="primary" size="lg" className="w-full"> <Calendar size={20} className="mr-sm" /> {selectedTime} 예약하기 </Button> )} </div> ); }

예제 4: 예약 취소 확인 다이얼로그

import "@vortex/ui-cals/theme"; import { Button } from "@vortex/ui-cals"; import { X, AlertTriangle } from "lucide-react"; export default function CancelReservationDialog() { const [loading, setLoading] = useState(false); const handleCancel = async () => { setLoading(true); await cancelReservation(); setLoading(false); }; return ( <Dialog> <DialogContent> <DialogHeader> <AlertTriangle size={24} className="text-warning" /> <h3>예약 취소 확인</h3> </DialogHeader> <p> 정말로 이 예약을 취소하시겠습니까? 취소 후에는 되돌릴 수 없습니다. </p> <div className="bg-muted p-md rounded-md"> <p className="text-sm"> <strong>예약 번호:</strong> #12345 </p> <p className="text-sm"> <strong>예약일시:</strong> 2024-01-20 14:00 </p> <p className="text-sm"> <strong>고객명:</strong> 홍길동 </p> </div> <DialogFooter className="flex gap-md"> <Button variant="outline">돌아가기</Button> <Button variant="cancelled" loading={loading} onClick={handleCancel}> <X size={16} className="mr-xs" /> {loading ? "취소 처리 중..." : "예약 취소"} </Button> </DialogFooter> </DialogContent> </Dialog> ); }

관련 컴포넌트

Last updated on