diff --git a/frontend/docs/features/components/Button.md b/frontend/docs/features/components/Button.md new file mode 100644 index 000000000..ed395c980 --- /dev/null +++ b/frontend/docs/features/components/Button.md @@ -0,0 +1,42 @@ +# Button 컴포넌트 + +공용 버튼 컴포넌트. `React.ButtonHTMLAttributes`를 extend하여 HTML 버튼의 모든 속성을 지원한다. + +## Props + +| Prop | Type | Default | 설명 | +| ---------- | ---------------------------- | -------- | ------------------------------------------------------------------------ | +| `width` | `string` | `'auto'` | 버튼 너비 (예: `'100%'`, `'150px'`) | +| `animated` | `boolean` | `false` | hover 시 pulse 애니메이션, active 시 scale 축소 | +| 그 외 | `React.ButtonHTMLAttributes` | — | `type`, `disabled`, `onClick`, `aria-*`, `data-*` 등 모든 HTML 버튼 속성 | + +## 사용 예시 + +```tsx +// 기본 + + +// 너비 지정 + submit + + +// 애니메이션 + 비활성화 + +``` + +## 스타일 + +테마 시스템(`theme.colors`, `theme.typography`)을 참조한다. + +- 배경: `gray[900]` (#3A3A3A) +- 텍스트: `base.white` +- 높이: 42px, border-radius: 10px +- 폰트: `typography.paragraph.p2` (16px, weight 600) +- disabled: `gray[500]` 배경, `gray[600]` 텍스트 + +## 관련 코드 + +- `src/components/common/Button/Button.tsx` — 컴포넌트 구현 +- `src/styles/theme/colors.ts` — 색상 토큰 +- `src/styles/theme/typography.ts` — 타이포그래피 토큰 diff --git a/frontend/src/components/common/Button/Button.tsx b/frontend/src/components/common/Button/Button.tsx index 61fe7eba5..e969ec10a 100644 --- a/frontend/src/components/common/Button/Button.tsx +++ b/frontend/src/components/common/Button/Button.tsx @@ -1,71 +1,62 @@ +import type { ButtonHTMLAttributes } from 'react'; import styled, { css, keyframes } from 'styled-components'; -export interface ButtonProps { +export interface ButtonProps extends ButtonHTMLAttributes { width?: string; - children: React.ReactNode; - type?: string; - onClick?: () => void; animated?: boolean; - disabled?: boolean; - className?: string; } const pulse = keyframes` - 0% { transform: scale(1); background-color: #3a3a3a; } - 50% { transform: scale(1.05); background-color: #505050; } - 100% { transform: scale(1); background-color: #3a3a3a; } + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } + 100% { transform: scale(1); } `; -const StyledButton = styled.button` - background-color: #3a3a3a; - color: #ffffff; +const StyledButton = styled.button<{ $animated: boolean; $width?: string }>` + display: inline-flex; + align-items: center; + justify-content: center; + background-color: ${({ theme }) => theme.colors.gray[900]}; + color: ${({ theme }) => theme.colors.base.white}; height: 42px; - border-radius: 10px; + padding: 0 16px; border: none; - font-weight: 600; - font-size: 16px; + border-radius: 10px; + font-size: ${({ theme }) => theme.typography.paragraph.p2.size}; + font-weight: ${({ theme }) => theme.typography.paragraph.p2.weight}; cursor: pointer; transition: background-color 0.2s; - width: ${({ width }) => width || 'auto'}; + width: ${({ $width }) => $width ?? 'auto'}; - &:hover { - background-color: #333333; - ${({ animated }) => - animated && + &:hover:not(:disabled) { + background-color: ${({ theme }) => theme.colors.gray[800]}; + ${({ $animated }) => + $animated && css` animation: ${pulse} 0.4s ease-in-out; `} } - &:active { - transform: ${({ animated }) => (animated ? 'scale(0.95)' : 'none')}; + &:active:not(:disabled) { + transform: ${({ $animated }) => ($animated ? 'scale(0.95)' : 'none')}; } &:disabled { - background-color: #cccccc; /* 비활성화된 느낌의 회색 */ - color: #666666; - cursor: not-allowed; /* 클릭할 수 없음을 나타내는 커서 */ + background-color: ${({ theme }) => theme.colors.gray[500]}; + color: ${({ theme }) => theme.colors.gray[600]}; + cursor: not-allowed; opacity: 0.7; } `; const Button = ({ width, - children, - onClick, - type, animated = false, - disabled = false, - className, + type = 'button', + children, + ...rest }: ButtonProps) => ( - + {children} );