react-common-components-library
Version:
모던하고 접근성 높은 컴포넌트 라이브러리입니다.
1,862 lines (1,631 loc) • 92.2 kB
Markdown
# React Common Components Library
모던하고 접근성 높은 React 컴포넌트 라이브러리입니다.
## 설치
npm을 사용하여 패키지를 설치합니다:
```bash
npm install react-common-components-library
```
또는 yarn을 사용:
```bash
yarn add react-common-components-library
```
## 컴포넌트
### 1. Accordion
접을 수 있는 콘텐츠 패널을 제공하는 컴포넌트입니다.
#### 사용법
```jsx
import { Accordion } from 'react-common-components-library';
function App() {
// 기본 사용법
const items = [
{
title: "섹션 1",
content: "섹션 1의 내용입니다."
},
{
title: "섹션 2",
content: "섹션 2의 내용입니다."
}
];
// 커스텀 아이콘 예제
const customIcon = (isOpen) => (
<span>{isOpen ? '📖' : '📘'}</span>
);
return (
<div>
{/* 기본 사용법 */}
<Accordion items={items} className="custom-accordion" />
{/* 다중 선택 사용법 */}
<Accordion
items={items}
allowMultiple
defaultExpanded={[0]}
/>
{/* 커스텀 스타일 예제 */}
<Accordion
items={items}
titleClassName="custom-title"
contentClassName="custom-content"
itemClassName="custom-item"
disableAnimation={true}
itemGap={10}
/>
{/* 커스텀 아이콘 예제 */}
<Accordion
items={items}
customIcon={customIcon}
/>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `items` | `Array<{title: ReactNode, content: ReactNode}>` | 필수 | 아코디언 항목 목록 |
| `titleStyle` | `CSSProperties` | - | 제목 스타일 |
| `contentStyle` | `CSSProperties` | - | 내용 스타일 |
| `style` | `CSSProperties` | - | 컨테이너 스타일 |
| `className` | `string` | '' | 아코디언 컨테이너에 적용할 추가 CSS 클래스 |
| `titleClassName` | `string` | '' | 아코디언 제목에 적용할 추가 CSS 클래스 |
| `contentClassName` | `string` | '' | 아코디언 내용에 적용할 추가 CSS 클래스 |
| `itemClassName` | `string` | '' | 아코디언 항목에 적용할 추가 CSS 클래스 |
| `iconClassName` | `string` | '' | 아코디언 화살표 아이콘에 적용할 추가 CSS 클래스 |
| `customIcon` | `(isOpen: boolean) => ReactNode` | - | 커스텀 화살표 아이콘 컴포넌트 |
| `disableAnimation` | `boolean` | false | 애니메이션 비활성화 여부 |
| `allowMultiple` | `boolean` | false | 여러 항목을 동시에 열 수 있는지 여부 |
| `defaultExpanded` | `number \| number[]` | - | 기본적으로 펼쳐진 항목의 인덱스 또는 인덱스 배열 |
| `onItemClick` | `(index: number, isOpen: boolean) => void` | - | 항목을 클릭할 때 호출되는 함수 |
| `itemGap` | `number` | 1 | 항목 간 간격 (픽셀) |
| `itemStyle` | `CSSProperties` | - | 아코디언 항목 스타일 |
| `iconStyle` | `CSSProperties` | - | 아이콘 스타일 |
### 2. AlertDialog
모달 형태의 경고 대화 상자를 제공하는 컴포넌트입니다.
#### 사용법
```jsx
import { AlertDialog } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={() => setIsOpen(true)}>대화 상자 열기</button>
<AlertDialog
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="정말 삭제하시겠습니까?"
description="이 작업은 취소할 수 없으며 데이터가 영구적으로 삭제됩니다."
cancelText="취소"
confirmText="삭제"
onConfirm={() => console.log('삭제됨')}
className="custom-dialog"
overlayClassName="custom-overlay"
/>
</>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `isOpen` | `boolean` | 필수 | 대화 상자 표시 여부 |
| `onClose` | `() => void` | 필수 | 닫기 핸들러 |
| `title` | `ReactNode` | "Are you sure absolutely sure?" | 제목 |
| `description` | `ReactNode` | "This action cannot be undone..." | 설명 |
| `cancelText` | `string` | "Cancel" | 취소 버튼 텍스트 |
| `confirmText` | `string` | "Continue" | 확인 버튼 텍스트 |
| `onCancel` | `() => void` | - | 취소 버튼 클릭 핸들러 |
| `onConfirm` | `() => void` | - | 확인 버튼 클릭 핸들러 |
| `style` | `CSSProperties` | - | 대화 상자 스타일 |
| `titleStyle` | `CSSProperties` | - | 제목 스타일 |
| `descriptionStyle` | `CSSProperties` | - | 설명 스타일 |
| `actionsStyle` | `CSSProperties` | - | 버튼 영역 스타일 |
| `cancelButtonStyle` | `CSSProperties` | - | 취소 버튼 스타일 |
| `confirmButtonStyle` | `CSSProperties` | - | 확인 버튼 스타일 |
| `overlayStyle` | `CSSProperties` | - | 오버레이 스타일 |
| `className` | `string` | '' | 대화 상자에 적용할 추가 CSS 클래스 |
| `overlayClassName` | `string` | '' | 오버레이에 적용할 추가 CSS 클래스 |
### 3. AspectRatio
지정된 가로세로 비율을 유지하는 컨테이너를 제공하는 컴포넌트입니다.
#### 사용법
```jsx
import { AspectRatio } from 'react-common-components-library';
function App() {
return (
<div style={{ width: '300px' }}>
<AspectRatio ratio={16} heightRatio={9}>
<img
src="https://example.com/image.jpg"
alt="예시 이미지"
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
/>
</AspectRatio>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `ratio` | `number` | 필수 | 가로 비율 |
| `heightRatio` | `number` | 1 | 세로 비율 |
| `children` | `ReactNode` | 필수 | 컨테이너 내부에 표시될 콘텐츠 |
| `className` | `string` | - | 추가 CSS 클래스 |
### 4. Avatar
사용자 프로필 이미지나 이니셜을 표시하는 컴포넌트입니다.
#### 사용법
```jsx
import { Avatar } from 'react-common-components-library';
function App() {
return (
<div style={{ display: 'flex', gap: '10px' }}>
{/* 이미지가 있는 아바타 */}
<Avatar
src="https://example.com/avatar.jpg"
alt="사용자 이름"
size="md"
/>
{/* 이미지 없이 이니셜을 표시하는 아바타 */}
<Avatar
alt="홍길동"
size="lg"
shape="square"
online={true}
/>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `src` | `string` | - | 아바타에 표시할 이미지 URL |
| `alt` | `string` | '' | 이미지가 없을 경우 표시할 대체 텍스트 (이니셜) |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | 'md' | 아바타 크기 |
| `shape` | `'circle' \| 'square'` | 'circle' | 아바타 모양 |
| `bordered` | `boolean` | false | 아바타 테두리 표시 여부 |
| `online` | `boolean` | false | 온라인 상태 표시 여부 |
| `className` | `string` | - | 추가 CSS 클래스 |
### 5. Button
다양한 스타일과 기능을 가진 버튼 컴포넌트입니다.
#### 사용법
```jsx
import { Button } from 'react-common-components-library';
function App() {
return (
<div style={{ display: 'flex', gap: '10px', flexDirection: 'column' }}>
<Button variant="primary" onClick={() => alert('클릭됨')}>
기본 버튼
</Button>
<Button
variant="secondary"
size="lg"
fullWidth={true}
>
크고 넓은 버튼
</Button>
<Button
variant="outline"
leftIcon={<span>←</span>}
>
이전으로
</Button>
<Button
variant="ghost"
rightIcon={<span>→</span>}
>
다음으로
</Button>
<Button
variant="primary"
isLoading={true}
>
로딩 중
</Button>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `children` | `ReactNode` | 필수 | 버튼 내용 |
| `variant` | `'primary' \| 'secondary' \| 'outline' \| 'ghost' \| 'link'` | 'primary' | 버튼 디자인 변형 |
| `size` | `'sm' \| 'md' \| 'lg'` | 'md' | 버튼 크기 |
| `fullWidth` | `boolean` | false | 버튼을 최대 너비로 확장할지 여부 |
| `isLoading` | `boolean` | false | 로딩 상태 표시 여부 |
| `leftIcon` | `ReactNode` | - | 버튼 왼쪽에 표시할 아이콘 |
| `rightIcon` | `ReactNode` | - | 버튼 오른쪽에 표시할 아이콘 |
| `className` | `string` | - | 추가 CSS 클래스 |
| + 기본 버튼 속성 | `ButtonHTMLAttributes<HTMLButtonElement>` | - | onClick, disabled 등 |
### 6. Checkbox
사용자가 하나 이상의 항목을 목록에서 선택할 수 있는 체크박스 컴포넌트입니다.
#### 사용법
```jsx
import { Checkbox } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [checked, setChecked] = useState(false);
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
<Checkbox
checked={checked}
onChange={(e) => setChecked(e.target.checked)}
>
이용 약관에 동의합니다
</Checkbox>
<Checkbox disabled>
비활성화된 체크박스
</Checkbox>
<Checkbox indeterminate>
부분 선택된 체크박스
</Checkbox>
<Checkbox error>
에러 상태 체크박스
</Checkbox>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `children` | `ReactNode` | - | 체크박스 라벨 |
| `size` | `'sm' \| 'md' \| 'lg'` | 'md' | 체크박스 크기 |
| `indeterminate` | `boolean` | false | 체크박스 인디터미네이트(부분 선택) 상태 |
| `error` | `boolean` | false | 에러 상태 표시 |
| `className` | `string` | '' | 체크박스 입력에 적용할 추가 CSS 클래스 |
| `wrapperClassName` | `string` | '' | 체크박스 컨테이너에 적용할 추가 CSS 클래스 |
| + 기본 input 속성 | `InputHTMLAttributes<HTMLInputElement>` | - | checked, onChange, disabled 등 |
### 7. Collapsible
첫 번째 항목은 항상 표시하고 나머지 항목들은 토글 버튼으로 표시/숨김을 제어할 수 있는 컴포넌트입니다.
#### 사용법
```jsx
import { Collapsible } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [open, setOpen] = useState(false);
return (
<div style={{ width: '400px' }}>
{/* 기본 사용법 */}
<Collapsible
title="저장된 리포지토리"
firstItem="@radix-ui/primitives"
restItems={[
"@radix-ui/colors",
"@stitches/react",
"@tailwindcss/ui"
]}
/>
{/* 제어 컴포넌트 */}
<Collapsible
title="제어 컴포넌트 예제"
firstItem="항상 표시되는 첫 번째 항목"
restItems={[
"제어되는 항목 1",
"제어되는 항목 2",
"제어되는 항목 3"
]}
open={open}
onOpenChange={setOpen}
/>
{/* 커스텀 스타일링 */}
<Collapsible
title="커스텀 스타일 예제"
firstItem="커스텀 첫 번째 항목"
restItems={[
"커스텀 항목 1",
"커스텀 항목 2"
]}
titleClassName="custom-title"
firstItemClassName="custom-first-item"
itemClassName="custom-item"
toggleClassName="custom-toggle"
disableAnimation={true}
itemGap={20}
/>
{/* 커스텀 화살표 */}
<Collapsible
title="커스텀 화살표 예제"
firstItem="커스텀 화살표 항목"
restItems={["항목 1", "항목 2"]}
customUpArrow={<span>▲</span>}
customDownArrow={<span>▼</span>}
/>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `title` | `ReactNode` | 필수 | 컴포넌트 제목 |
| `firstItem` | `ReactNode` | 필수 | 항상 표시되는 첫 번째 항목 |
| `restItems` | `ReactNode[]` | 필수 | 토글로 표시/숨김 가능한 나머지 항목들 |
| `defaultOpen` | `boolean` | false | 초기 열림 상태 |
| `open` | `boolean` | - | 외부에서 제어할 경우 열림 상태 |
| `onOpenChange` | `(open: boolean) => void` | - | 열림 상태가 변경될 때 호출되는 콜백 |
| `className` | `string` | '' | 컴포넌트에 적용할 추가 CSS 클래스 |
| `titleClassName` | `string` | '' | 제목에 적용할 추가 CSS 클래스 |
| `toggleClassName` | `string` | '' | 토글 버튼에 적용할 추가 CSS 클래스 |
| `firstItemClassName` | `string` | '' | 첫 번째 항목에 적용할 추가 CSS 클래스 |
| `itemClassName` | `string` | '' | 나머지 항목들에 적용할 추가 CSS 클래스 |
| `arrowClassName` | `string` | '' | 화살표에 적용할 추가 CSS 클래스 |
| `customUpArrow` | `ReactNode` | - | 커스텀 위쪽 화살표 요소 |
| `customDownArrow` | `ReactNode` | - | 커스텀 아래쪽 화살표 요소 |
| `disableAnimation` | `boolean` | false | 애니메이션 비활성화 여부 |
| `itemGap` | `number` | 12 | 항목 간 간격 (픽셀) |
| `style` | `CSSProperties` | - | 컴포넌트에 적용할 인라인 스타일 |
| `titleStyle` | `CSSProperties` | - | 제목에 적용할 인라인 스타일 |
| `toggleStyle` | `CSSProperties` | - | 토글 버튼에 적용할 인라인 스타일 |
| `firstItemStyle` | `CSSProperties` | - | 첫 번째 항목에 적용할 인라인 스타일 |
| `itemStyle` | `CSSProperties` | - | 나머지 항목들에 적용할 인라인 스타일 |
### 8. Command
키보드 중심의 명령어 팔레트 컴포넌트로, macOS Spotlight 또는 VSCode 명령어 팔레트와 유사한 인터페이스를 제공합니다.
#### 사용법
```jsx
import { Command } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [isOpen, setIsOpen] = useState(false);
// 명령어 그룹 정의
const commandGroups = [
{
label: '자주 사용하는 기능',
items: [
{
id: 'calendar',
label: '캘린더',
icon: <CalendarIcon />, // 적절한 아이콘 컴포넌트 사용
onSelect: () => console.log('캘린더 선택됨'),
},
{
id: 'calculator',
label: '계산기',
icon: <CalculatorIcon />, // 적절한 아이콘 컴포넌트 사용
onSelect: () => console.log('계산기 선택됨'),
},
],
},
{
label: '설정',
items: [
{
id: 'profile',
label: '프로필',
shortcut: '⌘P',
icon: <ProfileIcon />, // 적절한 아이콘 컴포넌트 사용
onSelect: () => console.log('프로필 선택됨'),
},
{
id: 'settings',
label: '설정',
shortcut: '⌘S',
icon: <SettingsIcon />, // 적절한 아이콘 컴포넌트 사용
onSelect: () => console.log('설정 선택됨'),
},
],
},
];
return (
<>
<button onClick={() => setIsOpen(true)}>
명령어 팔레트 열기
</button>
<Command
isOpen={isOpen}
onClose={() => setIsOpen(false)}
groups={commandGroups}
placeholder="명령어 입력 또는 검색..."
/>
</>
);
}
// 아이콘 컴포넌트 예시
const CalendarIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"></rect>
<line x1="16" y1="2" x2="16" y2="6"></line>
<line x1="8" y1="2" x2="8" y2="6"></line>
<line x1="3" y1="10" x2="21" y2="10"></line>
</svg>
);
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `isOpen` | `boolean` | 필수 | 컴포넌트 열림 상태 |
| `onClose` | `() => void` | 필수 | 컴포넌트 닫기 핸들러 |
| `groups` | `CommandGroup[]` | 필수 | 명령어 그룹 목록 |
| `placeholder` | `string` | "Type a command or search..." | 검색 입력 필드 플레이스홀더 |
| `className` | `string` | '' | 컴포넌트에 적용할 추가 CSS 클래스 |
#### 타입
```typescript
interface CommandGroup {
/**
* 그룹 제목
*/
label: string;
/**
* 그룹에 속한 명령어 항목들
*/
items: CommandItem[];
}
interface CommandItem {
/**
* 항목의 고유 식별자
*/
id: string;
/**
* 항목에 표시될 이름
*/
label: string;
/**
* 항목의 아이콘
*/
icon: ReactNode;
/**
* 항목의 키보드 단축키 (선택 사항)
*/
shortcut?: string;
/**
* 항목 선택 시 실행할 작업
*/
onSelect: () => void;
}
```
### 9. ContextMenu
사용자 인터페이스에 맞춤형 컨텍스트 메뉴(우클릭 메뉴)를 제공하는 컴포넌트입니다.
#### 사용법
```jsx
import { ContextMenu } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [isOpen, setIsOpen] = useState(false);
const [position, setPosition] = useState({ x: 0, y: 0 });
// 메뉴 섹션 정의
const menuSections = [
{
items: [
{
type: 'normal',
label: '뒤로',
shortcut: '⌘[',
onClick: () => console.log('뒤로 클릭됨'),
},
{
type: 'normal',
label: '앞으로',
shortcut: '⌘]',
disabled: true,
},
{
type: 'normal',
label: '새로고침',
shortcut: '⌘R',
onClick: () => console.log('새로고침 클릭됨'),
},
],
},
{
items: [
{
type: 'checkbox',
label: '북마크 바 표시',
shortcut: '⌘⇧B',
checked: true,
onClick: () => console.log('북마크 바 토글됨'),
},
],
},
{
title: '사용자',
items: [
{
type: 'normal',
label: '홍길동',
onClick: () => console.log('홍길동 선택됨'),
},
{
type: 'normal',
label: '김철수',
onClick: () => console.log('김철수 선택됨'),
},
],
},
];
// 우클릭 핸들러
const handleContextMenu = (e) => {
e.preventDefault();
setIsOpen(true);
setPosition({ x: e.clientX, y: e.clientY });
};
return (
<div
style={{ width: '500px', height: '300px', background: '#f5f5f5' }}
onContextMenu={handleContextMenu}
>
이 영역에서 마우스 오른쪽 버튼을 클릭하세요
<ContextMenu
isOpen={isOpen}
onClose={() => setIsOpen(false)}
x={position.x}
y={position.y}
sections={menuSections}
/>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `isOpen` | `boolean` | 필수 | 메뉴 표시 여부 |
| `onClose` | `() => void` | 필수 | 메뉴 닫기 핸들러 |
| `sections` | `MenuSection[]` | 필수 | 메뉴 섹션 목록 |
| `x` | `number` | 필수 | 메뉴 표시 X 좌표 |
| `y` | `number` | 필수 | 메뉴 표시 Y 좌표 |
| `className` | `string` | '' | 컴포넌트에 적용할 추가 CSS 클래스 |
#### 타입
```typescript
type MenuItemType = 'normal' | 'separator' | 'checkbox';
interface MenuItem {
/**
* 메뉴 항목 ID (선택적)
*/
id?: string;
/**
* 메뉴 항목 타입
*/
type: MenuItemType;
/**
* 메뉴 항목에 표시될 레이블
*/
label?: ReactNode;
/**
* 메뉴 항목 비활성화 여부
*/
disabled?: boolean;
/**
* 메뉴 항목 클릭시 실행할 작업
*/
onClick?: () => void;
/**
* 키보드 단축키 표시 (선택적)
*/
shortcut?: string;
/**
* 체크 여부 (checkbox 타입에서만 사용)
*/
checked?: boolean;
/**
* 서브메뉴 항목들 (선택적)
*/
items?: MenuItem[];
/**
* 항목 앞에 표시할 아이콘 (선택적)
*/
icon?: ReactNode;
}
interface MenuSection {
/**
* 섹션 제목 (선택적)
*/
title?: string;
/**
* 섹션에 포함된 메뉴 항목들
*/
items: MenuItem[];
}
```
### 10. Dialog
사용자를 중요한 내용으로 중단시키고 응답을 기대하는 모달 다이얼로그입니다. 주의를 필요로 하는 중요한 정보를 표시하거나 사용자의 결정이 필요한 상황에서 사용합니다. 폼 레이아웃을 포함할 수 있어 프로필 편집과 같은 작업에도 적합합니다.
#### 사용법
```jsx
import { Dialog, FormField } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [isOpen, setIsOpen] = useState(false);
return (
<div>
<button onClick={() => setIsOpen(true)}>
다이얼로그 열기
</button>
{/* 기본 다이얼로그 */}
<Dialog
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="다이얼로그 제목"
description="이것은 기본 다이얼로그 내용입니다. 모달 형태로 표시되며 배경을 클릭하거나 ESC 키를 눌러 닫을 수 있습니다."
footer={
<div>
<button onClick={() => setIsOpen(false)}>
취소
</button>
<button
onClick={() => {
alert('확인 버튼이 클릭되었습니다.');
setIsOpen(false);
}}
>
확인
</button>
</div>
}
>
<p>다이얼로그 내용을 여기에 작성합니다.</p>
</Dialog>
{/* 프로필 편집 폼 */}
<Dialog
isOpen={isOpen}
onClose={() => setIsOpen(false)}
title="Edit profile"
description="Make changes to your profile here. Click save when you're done."
onSubmit={(e) => {
e.preventDefault();
// 폼 데이터 처리
setIsOpen(false);
}}
>
<FormField label="Name">
<input
type="text"
name="name"
defaultValue="Email"
placeholder="Enter your name"
/>
</FormField>
<FormField label="Username">
<input
type="text"
name="username"
defaultValue="@peduarte"
placeholder="Enter your username"
/>
</FormField>
</Dialog>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `isOpen` | `boolean` | 필수 | 다이얼로그 열림 상태 |
| `onClose` | `() => void` | 필수 | 다이얼로그 닫기 핸들러 |
| `title` | `ReactNode` | - | 다이얼로그 제목 |
| `description` | `ReactNode` | - | 다이얼로그 설명 또는 내용 |
| `children` | `ReactNode` | - | 다이얼로그 내용 (description과 함께 사용 가능) |
| `footer` | `ReactNode` | - | 하단 버튼 또는 액션 영역 |
| `submitText` | `string` | "Save changes" | 제출 버튼 텍스트 |
| `onSubmit` | `(e: React.FormEvent) => void` | - | 폼 제출 핸들러 |
| `closeOnOverlayClick` | `boolean` | true | 배경 클릭시 닫기 허용 여부 |
| `closeOnEsc` | `boolean` | true | ESC 키로 닫기 허용 여부 |
| `className` | `string` | '' | 컴포넌트에 적용할 추가 CSS 클래스 |
| `overlayClassName` | `string` | '' | 오버레이에 적용할 추가 CSS 클래스 |
| `titleClassName` | `string` | '' | 제목에 적용할 추가 CSS 클래스 |
| `contentClassName` | `string` | '' | 내용에 적용할 추가 CSS 클래스 |
| `footerClassName` | `string` | '' | 하단 영역에 적용할 추가 CSS 클래스 |
| `width` | `string` | - | 다이얼로그 너비 (px 또는 %) |
| `maxWidth` | `string` | '500px' | 다이얼로그 최대 너비 (px 또는 %) |
| `style` | `CSSProperties` | - | 다이얼로그 컨테이너에 적용할 스타일 |
#### FormField Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `label` | `ReactNode` | 필수 | 필드 레이블 |
| `children` | `ReactNode` | 필수 | 필드 입력 요소 |
| `labelClassName` | `string` | '' | 레이블에 적용할 추가 CSS 클래스 |
| `className` | `string` | '' | 필드 컨테이너에 적용할 추가 CSS 클래스 |
### 11. DropdownMenu
드롭다운 메뉴를 제공하는 컴포넌트입니다. 계층적인 메뉴 구조, 아이콘, 단축키, 하위 메뉴 등을 지원합니다.
#### 사용법
```jsx
import { DropdownMenu } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [isOpen, setIsOpen] = useState(false);
// 아이콘 컴포넌트 정의
const ProfileIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
);
const SettingsIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<circle cx="12" cy="12" r="3"></circle>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
</svg>
);
const LogoutIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
<polyline points="16 17 21 12 16 7"></polyline>
<line x1="21" y1="12" x2="9" y2="12"></line>
</svg>
);
const HelpIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<circle cx="12" cy="12" r="10"></circle>
<path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path>
<line x1="12" y1="17" x2="12.01" y2="17"></line>
</svg>
);
const ChatIcon = () => (
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg>
);
return (
<div>
{/* 기본 사용법 */}
<DropdownMenu
title="내 계정"
isOpen={isOpen}
onClose={() => setIsOpen(false)}
sections={[
{
items: [
{
id: 'profile',
label: '프로필',
icon: <ProfileIcon />,
onClick: () => console.log('프로필 클릭됨')
},
{
id: 'settings',
label: '설정',
icon: <SettingsIcon />,
shortcut: '⌘S',
onClick: () => console.log('설정 클릭됨')
},
]
},
{
items: [
{
id: 'logout',
label: '로그아웃',
icon: <LogoutIcon />,
onClick: () => console.log('로그아웃 클릭됨')
},
]
}
]}
trigger={
<button onClick={() => setIsOpen(!isOpen)}>
계정 메뉴
</button>
}
/>
{/* 서브메뉴 사용 예제 */}
<DropdownMenu
title="지움말 메뉴"
isOpen={isOpen}
onClose={() => setIsOpen(false)}
sections={[
{
items: [
{
id: 'support',
label: '고객 지움',
icon: <HelpIcon />,
hasSubmenu: true, // 선택적으로 사용 가능
subItems: [
{
id: 'help',
label: '도움말 센터',
icon: <HelpIcon />,
onClick: () => console.log('도움말 센터 클릭됨')
},
{
id: 'chat',
label: '실시간 채팅',
icon: <ChatIcon />,
onClick: () => console.log('실시간 채팅 클릭됨')
}
]
}
]
}
]}
trigger={
<button onClick={() => setIsOpen(!isOpen)}>
지움말 메뉴
</button>
}
/>
{/* 다양한 위치 옵션 */}
<DropdownMenu
title="메뉴 위치"
isOpen={isOpen}
onClose={() => setIsOpen(false)}
position="bottom-end"
sections={[
{
items: [
{ id: 'item1', label: '항목 1', onClick: () => {} },
{ id: 'item2', label: '항목 2', onClick: () => {} },
]
}
]}
trigger={<button onClick={() => setIsOpen(!isOpen)}>오른쪽 정렬 메뉴</button>}
/>
{/* 섹션 제목 사용 */}
<DropdownMenu
isOpen={isOpen}
onClose={() => setIsOpen(false)}
sections={[
{
title: "계정 설정",
items: [
{ id: 'profile', label: '프로필', onClick: () => {} },
{ id: 'settings', label: '설정', onClick: () => {} },
]
},
{
title: "지움말",
items: [
{ id: 'help', label: '도움말', onClick: () => {} },
{ id: 'feedback', label: '피드백 보내기', onClick: () => {} },
]
}
]}
trigger={<button onClick={() => setIsOpen(!isOpen)}>섹션 메뉴</button>}
/>
</div>
);
}
```
#### Props
##### DropdownMenuProps
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `title` | `ReactNode` | - | 드롭다운 메뉴 제목 |
| `sections` | `DropdownMenuSection[]` | 필수 | 드롭다운 메뉴 섹션들 |
| `isOpen` | `boolean` | 필수 | 메뉴 열림 상태 |
| `onClose` | `() => void` | 필수 | 메뉴 닫기 핸들러 |
| `trigger` | `ReactNode` | - | 트리거 요소 (드롭다운을 열기 위한 버튼/요소) |
| `className` | `string` | '' | 컴포넌트에 적용할 추가 CSS 클래스 |
| `menuClassName` | `string` | '' | 메뉴 컨테이너에 적용할 추가 CSS 클래스 |
| `width` | `string` | '300px' | 메뉴의 너비 |
| `position` | `'bottom-start' \| 'bottom-end' \| 'top-start' \| 'top-end' \| 'right-start' \| 'left-start'` | 'bottom-start' | 메뉴가 트리거 요소 기준으로 표시될 위치 |
##### DropdownMenuSection
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `title` | `string` | - | 섹션 제목 (선택적) |
| `items` | `DropdownMenuItem[]` | 필수 | 섹션에 포함된 메뉴 항목들 |
| `className` | `string` | '' | 섹션에 적용할 추가 CSS 클래스 |
##### DropdownMenuItem
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `id` | `string` | 필수 | 메뉴 항목의 고유 ID |
| `label` | `string` | 필수 | 메뉴 항목에 표시될 레이블 |
| `icon` | `ReactNode` | - | 항목의 아이콘 |
| `shortcut` | `string` | - | 단축키 표시 |
| `onClick` | `() => void` | - | 항목 클릭 시 실행할 작업 |
| `hasSubmenu` | `boolean` | false | 하위 메뉴가 있는지 여부 |
| `subItems` | `DropdownMenuItem[]` | - | 하위 메뉴 항목들. 메뉴 항목에 마우스를 올리면 표시됨 |
| `disabled` | `boolean` | false | 비활성화 여부 |
| `className` | `string` | '' | 항목에 적용할 추가 CSS 클래스 |
### 12. HoverCard
마우스를 특정 요소 위에 올렸을 때 추가 정보를 카드 형태로 표시하는 컴포넌트입니다. SNS 프로필 미리보기, 용어 설명, 이미지 미리보기 등 다양한 상황에서 활용할 수 있습니다.
#### 사용법
```jsx
import { HoverCard } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [isHovered, setIsHovered] = useState(false);
return (
<div style={{ padding: '50px', fontFamily: 'Arial' }}>
{/* 기본 사용법 */}
<div style={{ marginBottom: '30px' }}>
<HoverCard
trigger={<span style={{ fontWeight: 'bold', color: '#6366f1' }}>@홍길동</span>}
content={
<div style={{ display: 'flex', flexDirection: 'column', gap: '10px' }}>
<div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
<img
src="https://i.pravatar.cc/100"
alt="홍길동"
style={{ width: '48px', height: '48px', borderRadius: '24px' }}
/>
<div>
<div style={{ fontWeight: 'bold' }}>홍길동</div>
<div style={{ color: '#666' }}>@honggildong</div>
</div>
</div>
<div>프론트엔드 개발자 | React, TypeScript 전문</div>
<div style={{ display: 'flex', gap: '10px' }}>
<div>팔로워: 1,234</div>
<div>팔로잉: 567</div>
</div>
</div>
}
/>
<span> 님이 새 글을 작성했습니다.</span>
</div>
{/* 다양한 위치 옵션 */}
<div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: '30px' }}>
<HoverCard
trigger={<button>Top</button>}
content={<div>상단에 표시되는 호버 카드입니다.</div>}
position="top"
/>
<HoverCard
trigger={<button>Right</button>}
content={<div>오른쪽에 표시되는 호버 카드입니다.</div>}
position="right"
/>
<HoverCard
trigger={<button>Bottom</button>}
content={<div>하단에 표시되는 호버 카드입니다.</div>}
position="bottom"
/>
<HoverCard
trigger={<button>Left</button>}
content={<div>왼쪽에 표시되는 호버 카드입니다.</div>}
position="left"
/>
</div>
{/* 지연 시간 설정 */}
<div style={{ marginBottom: '30px' }}>
<HoverCard
trigger={<button>빠른 표시 (지연 100ms)</button>}
content={<div>마우스를 올리면 빠르게 표시됩니다.</div>}
openDelay={100}
closeDelay={500}
/>
</div>
{/* 제어 컴포넌트 */}
<div style={{ marginBottom: '30px' }}>
<button
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
제어 컴포넌트
</button>
<HoverCard
trigger={<span />} // 빈 트리거 사용
content={<div>상태로 제어되는 호버 카드입니다.</div>}
open={isHovered}
onOpenChange={setIsHovered}
position="right"
/>
</div>
{/* 커스텀 스타일링 */}
<div>
<HoverCard
trigger={<span style={{ color: 'purple', textDecoration: 'underline' }}>용어 설명</span>}
content={
<div>
<h4 style={{ margin: '0 0 8px 0' }}>호버 카드</h4>
<p style={{ margin: 0 }}>마우스를 특정 요소 위에 올렸을 때 추가 정보를 제공하는 UI 요소입니다.</p>
</div>
}
cardStyle={{
background: 'linear-gradient(45deg, #6366f1, #8b5cf6)',
color: 'white',
border: 'none'
}}
showArrow={true}
arrowClassName="custom-arrow"
width="300px"
/>
</div>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `trigger` | `ReactNode` | 필수 | 호버 시 카드가 표시될 트리거 요소 |
| `content` | `ReactNode` | 필수 | 호버 카드에 표시될 내용 |
| `openDelay` | `number` | 300 | 카드가 표시되기까지의 지연 시간 (밀리초) |
| `closeDelay` | `number` | 300 | 카드가 닫히기까지의 지연 시간 (밀리초) |
| `position` | `'top' \| 'bottom' \| 'left' \| 'right'` | 'bottom' | 카드 위치 |
| `open` | `boolean` | - | 외부에서 제어할 때 사용하는 열림 상태 |
| `onOpenChange` | `(open: boolean) => void` | - | 열림 상태가 변경될 때 호출되는 콜백 |
| `width` | `string \| number` | - | 카드 너비 |
| `style` | `CSSProperties` | - | 부모 요소 스타일 |
| `cardStyle` | `CSSProperties` | - | 카드 스타일 |
| `className` | `string` | '' | 부모 요소에 적용할 추가 CSS 클래스 |
| `cardClassName` | `string` | '' | 카드에 적용할 추가 CSS 클래스 |
| `inPortal` | `boolean` | false | 카드가 트리거보다 앞에 렌더링될지 여부 |
| `showArrow` | `boolean` | true | 화살표 표시 여부 |
| `arrowClassName` | `string` | '' | 화살표에 적용할 추가 CSS 클래스 |
| `arrowStyle` | `CSSProperties` | - | 화살표 스타일 |
### 13. Input
사용자로부터 텍스트 입력을 받기 위한 컴포넌트입니다.
#### 사용법
```jsx
import { Input } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [email, setEmail] = useState('');
return (
<div style={{ padding: '20px', maxWidth: '600px' }}>
{/* 기본 사용법 */}
<Input
label="이메일"
placeholder="example@email.com"
value={email}
onChange={(e) => setEmail(e.target.value)}
helperText="업무용 이메일을 입력해주세요"
/>
{/* 에러 상태 */}
<Input
label="비밀번호"
type="password"
placeholder="비밀번호 입력"
error="비밀번호는 8자 이상이어야 합니다"
style={{ marginTop: '20px' }}
/>
{/* 성공 상태 */}
<Input
label="사용자명"
value="johndoe"
success
helperText="사용 가능한 사용자명입니다"
style={{ marginTop: '20px' }}
/>
{/* 어도먼트 사용 */}
<Input
label="금액"
startAdornment="₩"
placeholder="0"
style={{ marginTop: '20px' }}
/>
<Input
label="웹사이트"
endAdornment=".com"
placeholder="example"
style={{ marginTop: '20px' }}
/>
{/* 다양한 크기 */}
<div style={{ display: 'flex', gap: '20px', marginTop: '20px' }}>
<Input size="sm" placeholder="작은 입력" />
<Input size="md" placeholder="중간 입력" />
<Input size="lg" placeholder="큰 입력" />
</div>
{/* 다양한 변형 */}
<div style={{ display: 'flex', flexDirection: 'column', gap: '20px', marginTop: '20px' }}>
<Input variant="outlined" placeholder="Outlined Input" />
<Input variant="filled" placeholder="Filled Input" />
<Input variant="standard" placeholder="Standard Input" />
</div>
{/* 구독 양식 예제 */}
<div style={{ marginTop: '40px' }}>
<h3>Email</h3>
<div style={{ display: 'flex' }}>
<Input
placeholder="Email"
fullWidth
style={{
borderTopRightRadius: 0,
borderBottomRightRadius: 0,
}}
/>
<button
style={{
padding: '10px 20px',
background: '#0f172a',
color: 'white',
border: 'none',
borderTopRightRadius: '8px',
borderBottomRightRadius: '8px',
fontWeight: 'bold',
cursor: 'pointer',
}}
>
Subscribe
</button>
</div>
<p style={{ marginTop: '8px', color: '#64748b', fontSize: '14px' }}>
Enter your email address
</p>
</div>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `label` | `ReactNode` | - | Input에 나타날 레이블 |
| `error` | `string` | - | 에러 메시지 |
| `success` | `boolean` | false | 성공 상태 |
| `helperText` | `ReactNode` | - | 힌트 텍스트 |
| `startAdornment` | `ReactNode` | - | 입력 필드 앞에 표시할 아이콘이나 요소 |
| `endAdornment` | `ReactNode` | - | 입력 필드 뒤에 표시할 아이콘이나 요소 |
| `size` | `'sm' \| 'md' \| 'lg'` | 'md' | Input의 크기 |
| `variant` | `'outlined' \| 'filled' \| 'standard'` | 'outlined' | Input의 변형 |
| `fullWidth` | `boolean` | false | 가득 채우는 너비로 설정할지 여부 |
| `containerClassName` | `string` | '' | 컨테이너에 적용할 CSS 클래스 |
| `inputClassName` | `string` | '' | 입력 요소에 적용할 CSS 클래스 |
| `labelClassName` | `string` | '' | 레이블에 적용할 CSS 클래스 |
| `containerStyle` | `CSSProperties` | - | 컨테이너에 적용할 스타일 |
| `id` | `string` | - | 폼 ID 연결용 (레이블의 for 속성) |
Input 컴포넌트는 표준 HTML input 요소의 모든 속성도 지원합니다.
### 14. Label
레이블 컴포넌트는 입력 필드나 체크박스 같은 사용자 인터페이스 요소에 설명을 제공합니다.
#### 사용법
```jsx
import { Label } from 'react-common-components-library';
import { useState } from 'react';
function App() {
const [accepted, setAccepted] = useState(false);
return (
<div style={{ padding: '20px', maxWidth: '600px' }}>
{/* 기본 사용법 */}
<div style={{ marginBottom: '20px' }}>
<Label htmlFor="username">사용자명</Label>
<input id="username" type="text" style={{ display: 'block', marginTop: '8px', padding: '8px', width: '100%', borderRadius: '4px', border: '1px solid #ccc' }} />
</div>
{/* 체크박스 레이블 */}
<div style={{ marginBottom: '20px' }}>
<Label
hasCheckbox
checked={accepted}
onChange={(e) => setAccepted(e.target.checked)}
>
이용약관에 동의합니다
</Label>
</div>
{/* 필수 필드 */}
<div style={{ marginBottom: '20px' }}>
<Label htmlFor="email" required>이메일</Label>
<input id="email" type="email" required style={{ display: 'block', marginTop: '8px', padding: '8px', width: '100%', borderRadius: '4px', border: '1px solid #ccc' }} />
</div>
{/* 에러 상태 */}
<div style={{ marginBottom: '20px' }}>
<Label
hasCheckbox
checked={false}
error={true}
errorMessage="계속하려면 동의해야 합니다"
>
개인정보 처리방침에 동의합니다
</Label>
</div>
{/* 다양한 크기 */}
<div style={{ marginBottom: '20px' }}>
<div style={{ marginBottom: '10px' }}>
<Label size="sm" hasCheckbox>작은 레이블</Label>
</div>
<div style={{ marginBottom: '10px' }}>
<Label size="md" hasCheckbox>중간 레이블</Label>
</div>
<div>
<Label size="lg" hasCheckbox>큰 레이블</Label>
</div>
</div>
{/* Accept Terms and Condition 예제 */}
<div style={{ marginBottom: '20px' }}>
<Label
hasCheckbox
checked={accepted}
onChange={(e) => setAccepted(e.target.checked)}
labelClassName="terms-label"
checkboxClassName="terms-checkbox"
>
Accept terms and condition
</Label>
</div>
</div>
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `children` | `ReactNode` | 필수 | 레이블 내용 |
| `hasCheckbox` | `boolean` | false | 체크박스 포함 여부 |
| `required` | `boolean` | false | 필수 필드 여부 (별표 표시) |
| `size` | `'sm' \| 'md' \| 'lg'` | 'md' | 레이블 크기 |
| `error` | `boolean` | false | 에러 상태 표시 |
| `errorMessage` | `string` | - | 에러 메시지 |
| `labelClassName` | `string` | '' | 레이블에 적용할 추가 클래스명 |
| `checkboxClassName` | `string` | '' | 체크박스에 적용할 추가 클래스명 |
| `checked` | `boolean` | - | 체크박스 상태 |
| `onChange` | `(e: React.ChangeEvent<HTMLInputElement>) => void` | - | 체크박스 상태 변경 핸들러 |
| `labelStyle` | `React.CSSProperties` | - | 레이블에 적용할 스타일 |
| `checkboxStyle` | `React.CSSProperties` | - | 체크박스에 적용할 스타일 |
| `htmlFor` | `string` | - | htmlFor 속성 (체크박스 ID 연결) |
| `id` | `string` | - | 체크박스 ID |
| `disabled` | `boolean` | false | 비활성화 상태 |
### 15. MenuBar
MenuBar 컴포넌트는 데스크톱 애플리케이션 스타일의 메뉴 인터페이스를 제공합니다. 수평으로 배치된 메뉴 항목과 드롭다운 메뉴, 키보드 단축키 등을 지원합니다.
#### 사용법
```jsx
import { MenuBar } from 'react-common-components-library';
function App() {
return (
<div style={{ padding: '20px' }}>
{/* 기본 사용법 */}
<MenuBar
items={[
{
id: 'file',
label: 'File',
items: [
{
id: 'new-tab',
label: 'New Tab',
shortcut: '⌘T',
onClick: () => console.log('New Tab clicked'),
},
{
id: 'new-window',
label: 'New Window',
shortcut: '⌘N',
onClick: () => console.log('New Window clicked'),
},
{
id: 'new-incognito',
label: 'New Incognito Window',
disabled: true,
},
{
id: 'separator-1',
isSeparator: true,
},
{
id: 'share',
label: 'Share',
items: [
{
id: 'email',
label: 'Email',
onClick: () => console.log('Email clicked'),
},
{
id: 'message',
label: 'Message',
onClick: () => console.log('Message clicked'),
},
],
},
{
id: 'separator-2',
isSeparator: true,
},
{
id: 'print',
label: 'Print...',
shortcut: '⌘P',
onClick: () => console.log('Print clicked'),
},
],
},
{
id: 'edit',
label: 'Edit',
items: [
{
id: 'undo',
label: 'Undo',
shortcut: '⌘Z',
onClick: () => console.log('Undo clicked'),
},
{
id: 'redo',
label: 'Redo',
shortcut: '⌘⇧Z',
onClick: () => console.log('Redo clicked'),
},
],
},
{
id: 'view',
label: 'View',
items: [
{
id: 'zoom-in',
label: 'Zoom In',
shortcut: '⌘+',
onClick: () => console.log('Zoom In clicked'),
},
{
id: 'zoom-out',
label: 'Zoom Out',
shortcut: '⌘-',
onClick: () => console.log('Zoom Out clicked'),
},
],
},
{
id: 'profile',
label: 'Profile',
items: [
{
id: 'account',
label: 'Account',
onClick: () => console.log('Account clicked'),
},
{
id: 'settings',
label: 'Settings',
onClick: () => console.log('Settings clicked'),
},
{
id: 'separator-3',
isSeparator: true,
},
{
id: 'logout',
label: 'Log Out',
onClick: () => console.log('Log Out clicked'),
},
],
},
]}
/>
{/* 비활성화된 항목 */}
<div style={{ marginTop: '60px' }}>
<MenuBar
items={[
{
id: 'file',
label: 'File',
items: [
{
id: 'new-tab',
label: 'New Tab',
onClick: () => console.log('New Tab clicked'),
},
{
id: 'incognito-window',
label: 'Incognito Window',
disabled: true,
},
],
},
{
id: 'edit',
label: 'Edit',
disabled: true,
items: [],
},
]}
/>
</div>
</div>
);
}
```
#### Props
##### MenuBar
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `items` | `MenuBarItemProps[]` | 필수 | 메뉴바 아이템 배열 |
| `className` | `string` | '' | 메뉴바에 적용할 추가 CSS 클래스 |
| `style` | `React.CSSProperties` | - | 메뉴바에 적용할 스타일 |
| `width` | `string` | 'max-content' | 메뉴바의 너비. '100%', '300px' 등 CSS 너비 값 사용 가능 |
##### MenuBarItemProps
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `id` | `string` | 필수 | 메뉴 아이템 ID |
| `label` | `string` | 필수 | 메뉴 아이템 레이블 |
| `disabled` | `boolean` | false | 메뉴 아이템 비활성화 여부 |
| `items` | `MenuItemProps[]` | - | 서브메뉴 항목 |
| `className` | `string` | '' | 메뉴 아이템에 적용할 추가 CSS 클래스 |
##### MenuItemProps
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `id` | `string` | 필수 | 메뉴 항목의 고유 ID |
| `label` | `string` | 필수 | 메뉴 항목에 표시될 레이블 |
| `icon` | `ReactNode` | - | 항목의 아이콘 |
| `shortcut` | `string` | - | 단축키 표시 |
| `onClick` | `() => void` | - | 항목 클릭 시 실행할 작업 |
| `hasSubmenu` | `boolean` | false | 하위 메뉴가 있는지 여부 |
| `subItems` | `MenuItemProps[]` | - | 하위 메뉴 항목들. 메뉴 항목에 마우스를 올리면 표시됨 |
| `disabled` | `boolean` | false | 비활성화 여부 |
| `className` | `string` | '' | 항목에 적용할 추가 CSS 클래스 |
### 16. NavigationMenu
NavigationMenu 컴포넌트는 웹사이트의 주요 네비게이션 영역을 구성하는 데 사용됩니다. 드롭다운 메뉴와 링크 목록을 포함할 수 있으며, 사용자가 웹사이트의 다양한 섹션으로 쉽게 이동할 수 있도록 도와줍니다.
#### 사용법
```jsx
import { NavigationMenu } from 'react-common-components-library';
function App() {
return (
<NavigationMenu
items={[
{
label: 'Getting started',
content: {
title: 'Introduction',
description: 'Re-usable components built using Radix UI and Tailwind CSS',
links: [
{
title: 'Introduction',
description: 'Re-usable components built using Radix UI and Tailwind CSS',
href: '/docs/introduction',
},
{
title: 'Installation',
description: 'How to install dependencies and structure your app.',
href: '/docs/installation',
},
],
},
active: true,
},
{
label: 'Components',
content: {
links: [
{
title: 'Accordion',
description: 'A vertically stacked set of interactive headings.',
href: '/docs/components/accordion',
},
{
title: 'Button',
description: 'Displays a button or a component that looks like a button.',
href: '/docs/components/button',
},
],
},
},
{
label: 'Blog',
href: '/blog',
},
]}
/>
);
}
```
#### Props
##### NavigationMenu
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `items` | `NavigationItemProps[]` | 필수 | 네비게이션 메뉴 항목 목록 |
| `className` | `string` | '' | 네비게이션 메뉴에 적용할 추가 CSS 클래스 |
| `style` | `React.CSSProperties` | - | 네비게이션 메뉴에 적용할 스타일 |
| `width` | `string` | '100%' | 네비게이션 메뉴의 너비 |
##### NavigationItemProps
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `label` | `string` | 필수 | 네비게이션 항목 제목 |
| `content` | `NavigationContent` | - | 네비게이션 항목 콘텐츠 (드롭다운 메뉴) |
| `href` | `string` | - | 네비게이션 항목 링크 URL (content가 없을 경우 사용) |
| `active` | `boolean` | false | 현재 활성화된 항목인지 여부 |
| `className` | `string` | '' | 네비게이션 항목에 적용할 추가 CSS 클래스 |
##### NavigationContent
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `title` | `string` | - | 콘텐츠 제목 |
| `description` | `string` | - | 콘텐츠 설명 |
| `links` | `NavigationLink[]` | - | 콘텐츠 내 링크 목록 |
| `customContent` | `React.ReactNode` | - | 커스텀 콘텐츠 |
### 17. Popover
Popover 컴포넌트는 특정 요소를 클릭했을 때 팝업 형태로 정보나 작업을 제공하는 컴포넌트입니다. 사용자에게 추가 정보를 표시하거나 설정을 변경할 수 있는 인터페이스를 제공합니다.
#### 사용법
```jsx
import { Popover, PopoverField } from 'react-common-components-library';
import { Button } from 'react-common-components-library';
function App() {
// 기본 사용법
return (
<Popover
trigger={<Button>클릭하세요</Button>}
title="팝오버 제목"
description="팝오버에 대한 설명입니다."
>
<div>팝오버 내용을 여기에 넣을 수 있습니다.</div>
</Popover>
);
}
// 치수 설정 예제
function DimensionsExample() {
const [width, setWidth] = useState('100%');
const [maxWidth, setMaxWidth] = useState('300px');
const [height, setHeight] = useState('25px');
const [maxHeight, setMaxHeight] = useState('none');
return (
<Popover
trigger={<Button>치수 설정</Button>}
title="치수 설정"
description="Set the dimensions for the layer."
width={260}
>
<PopoverField
label="Width"
value={width}
onChange={setWidth}
/>
<PopoverField
label="Max. width"
value={maxWidth}
onChange={setMaxWidth}
/>
<PopoverField
label="Height"
value={height}
onChange={setHeight}
/>
<PopoverField
label="Max. height"
value={maxHeight}
onChange={setMaxHeight}
/>
</Popover>
);
}
```
#### Props
##### Popover
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `trigger` | `ReactNode` | 필수 | Popover를 열기 위한 트리거 요소 |
| `title` | `ReactNode` | - | Popover의 제목 |
| `description` | `ReactNode` | - | Popover의 설명 |
| `children` | `ReactNode` | 필수 | Popover의 내용 |
| `defaultOpen` | `boolean` | false | Popover가 기본적으로 열려있는지 여부 |
| `open` | `boolean` | - | 외부에서 제어하는 열림 상태 |
| `onOpenChange` | `(open: boolean) => void` | - | 열림 상태가 변경될 때 호출되는 함수 |
| `closeOnOutsideClick` | `boolean` | true | 클릭 외부에서 Popover를 닫을지 여부 |
| `closeOnEscape` | `boolean` | true | ESC 키를 눌렀을 때 Popover를 닫을지 여부 |
| `width` | `string \| number` | - | Popover 컨텐츠의 너비 |
| `position` | `'top' \| 'right' \| 'bottom' \| 'left'` | 'bottom' | Popover가 열리는 위치 |
| `triggerClassName` | `string` | - | Popover 트리거에 적용할 클래스 |
| `contentClassName` | `string` | - | Popover 컨텐츠에 적용할 클래스 |
| `titleClassName` | `string` | - | Popover 제목에 적용할 클래스 |
| `descriptionClassName` | `string` | - | Popover 설명에 적용할 클래스 |
| `triggerStyle` | `CSSProperties` | - | Popover 트리거에 적용할 스타일 |
| `contentStyle` | `CSSProperties` | - | Popover 컨텐츠에 적용할 스타일 |
##### PopoverField
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `label` | `string` | 필수 | 필드 레이블 |
| `type` | `string` | 'text' | 입력 타입 |
| `value` | `string` | 필수 | 입력 값 |
| `onChange` | `(value: string) => void` | 필수 | 값이 변경될 때 호출되는 함수 |
| `placeholder` | `string` | - | 플레이스홀더 |
| `className` | `string` | - | 필드 클래스 |
### 18. Progress
Progress 컴포넌트는 작업의 완료 상태나 프로세스의 진행 상황을 시각적으로 표시하는 데 사용됩니다. 사용자에게 작업이 얼마나 진행되었는지 직관적으로 보여줍니다.
#### 사용법
```jsx
import { Progress } from 'react-common-components-library';
function App() {
// 기본 사용법
return (
<Progress value={60} />
);
// 레이블과 값 표시
return (
<Progress
value={60}
label="다운로드 진행률"
showValue
/>
);
// 다양한 크기와 색상
return (
<>
<Progress value={60} size="sm" color="primary" />
<Progress value={60} size="md" color="success" />
<Progress value={60} size="lg" color="danger" />
</>
);
// 애니메이션 효과
return (
<Progress value={60} animated />
);
}
```
#### Props
| 속성 | 타입 | 기본값 | 설명 |
|------|------|--------|------|
| `value` | `number` | 필수 | 진행률 (0-100) |
| `max` | `number` | 100 | 최대값 |
| `label` | `string` | - | 진행 바 위에 표시될 레이블 |
| `showValue` | `boolean` | false | 진행률 텍스트 표시 여부 |
| `valueFormat` | `string` | '{value}%' | 진행률 텍스트 형식 |
| `animated` | `boolean` | false | 애니메이션 효과 적용 여부 |
| `size` | `'sm' \| 'md' \| 'lg'` | 'md' | 진행 바 크기 |
| `color` | `'primary' \| 'secondary' \| 'success' \| 'da