@reopt-ai/opt-ui 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/COMPONENT_CATALOG.md +3000 -0
  3. package/LICENSE +21 -0
  4. package/README.md +244 -0
  5. package/dist/chunk-3GWWZKX7.js +38 -0
  6. package/dist/chunk-AFF2HPE5.cjs +5008 -0
  7. package/dist/chunk-ELWICXYY.js +4745 -0
  8. package/dist/chunk-N4NDU5ET.cjs +4745 -0
  9. package/dist/chunk-ONE3C5RV.cjs +38 -0
  10. package/dist/chunk-QWBHD54V.js +3218 -0
  11. package/dist/chunk-RBM2RNC2.js +5008 -0
  12. package/dist/chunk-X5WCXJAF.cjs +3218 -0
  13. package/dist/core/index.cjs +324 -0
  14. package/dist/core/index.d.cts +5 -0
  15. package/dist/core/index.d.ts +5 -0
  16. package/dist/core/index.js +324 -0
  17. package/dist/docs/01-getting-started.md +129 -0
  18. package/dist/docs/02-components/01-core.md +1841 -0
  19. package/dist/docs/02-components/02-visuals.md +11 -0
  20. package/dist/docs/02-components/03-shells.md +1361 -0
  21. package/dist/docs/02-components/04-surfaces.md +11 -0
  22. package/dist/docs/02-components/index.md +106 -0
  23. package/dist/docs/03-recipes/01-forms.md +471 -0
  24. package/dist/docs/03-recipes/02-dashboards.md +397 -0
  25. package/dist/docs/03-recipes/03-layouts.md +424 -0
  26. package/dist/docs/04-theming.md +232 -0
  27. package/dist/docs/05-migration/01-breaking-changes.md +117 -0
  28. package/dist/docs/05-migration/02-formstore.md +336 -0
  29. package/dist/docs/06-troubleshooting.md +119 -0
  30. package/dist/docs/index.md +71 -0
  31. package/dist/id-registry.cjs +1875 -0
  32. package/dist/id-registry.d.cts +27 -0
  33. package/dist/id-registry.d.ts +27 -0
  34. package/dist/id-registry.js +1875 -0
  35. package/dist/id-registry.json +3799 -0
  36. package/dist/index-BZ_lBlO1.d.ts +474 -0
  37. package/dist/index-BuvxoWHf.d.cts +474 -0
  38. package/dist/index-DlAcuvQp.d.cts +1686 -0
  39. package/dist/index-Slu5hOj1.d.ts +1686 -0
  40. package/dist/index.cjs +9959 -0
  41. package/dist/index.d.cts +2351 -0
  42. package/dist/index.d.ts +2351 -0
  43. package/dist/index.js +9959 -0
  44. package/dist/meta.cjs +6898 -0
  45. package/dist/meta.d.cts +36 -0
  46. package/dist/meta.d.ts +36 -0
  47. package/dist/meta.js +6869 -0
  48. package/dist/shells/index.cjs +65 -0
  49. package/dist/shells/index.d.cts +5 -0
  50. package/dist/shells/index.d.ts +5 -0
  51. package/dist/shells/index.js +65 -0
  52. package/dist/tailwind.css +401 -0
  53. package/dist/theme/presets/default.css +355 -0
  54. package/dist/theme/presets/minimal.css +354 -0
  55. package/dist/theme/presets/mono-dark.css +354 -0
  56. package/dist/theme/presets/natural.css +181 -0
  57. package/dist/theme/presets/pro.css +354 -0
  58. package/dist/types-D4-0lwaE.d.cts +298 -0
  59. package/dist/types-D4-0lwaE.d.ts +298 -0
  60. package/dist/visuals/index.cjs +4 -0
  61. package/dist/visuals/index.d.cts +1 -0
  62. package/dist/visuals/index.d.ts +1 -0
  63. package/dist/visuals/index.js +4 -0
  64. package/package.json +165 -0
@@ -0,0 +1,3000 @@
1
+ # @reopt-ai/opt-ui Component Catalog
2
+
3
+ <!-- DEPRECATED: Prefer dist/docs/02-components/ for per-layer reference. -->
4
+ <!-- Auto-generated from ComponentMeta. Do not edit. -->
5
+ <!-- Version: 1.4.1 -->
6
+
7
+ ## Quick Stats
8
+
9
+ | Layer | Count |
10
+ | --------- | ------- |
11
+ | Core | 59 |
12
+ | Visuals | 0 |
13
+ | Shells | 75 |
14
+ | Surfaces | 0 |
15
+ | **Total** | **134** |
16
+
17
+ ## Component Selection Guide
18
+
19
+ | 요구사항 | 추천 컴포넌트 | 레이어 |
20
+ | ------------------- | -------------------------------------------------- | ------------ |
21
+ | 텍스트 입력 | Input | Core |
22
+ | 멀티라인 텍스트 | Textarea | Core |
23
+ | 숫자 입력 | NumberInput | Core |
24
+ | 드롭다운 선택 | Select / StatusSelect / BranchSelect | Core / Shell |
25
+ | 검색 + 선택 | Combobox / SearchCombobox / AsyncCombobox | Core / Shell |
26
+ | 체크박스 | Checkbox / CheckboxGroup | Core |
27
+ | 라디오 버튼 | RadioGroup | Core |
28
+ | 토글 스위치 | Switch | Core |
29
+ | 날짜 범위 선택 | DateRangePicker | Core |
30
+ | 태그 입력 | TagInput | Core |
31
+ | 색상 선택 | ColorPicker | Core |
32
+ | 아이콘 선택 | IconPicker | Core |
33
+ | 데이터 테이블 | DataTable | Shell |
34
+ | 인라인 편집 테이블 | InlineEditTable | Shell |
35
+ | 트리/계층 테이블 | TreeTable | Shell |
36
+ | 칸반 보드 | KanbanBoard | Shell |
37
+ | 필터 바 | FilterBar | Shell |
38
+ | 필터 프리셋 저장 | SavedFilters | Shell |
39
+ | 일괄 작업 | BulkActions | Shell |
40
+ | 컬럼 표시 토글 | ColumnToggler | Shell |
41
+ | 시간 범위 선택 | TimeRangeSelector | Shell |
42
+ | A/B 비교 선택 | ComparisonSelector | Shell |
43
+ | 선 차트 / 영역 차트 | LineChart / AreaChart | Visual |
44
+ | 막대 차트 | BarChart | Visual |
45
+ | 파이/도넛 차트 | PieChart | Visual |
46
+ | 인라인 스파크라인 | Sparkline | Visual |
47
+ | 흐름 다이어그램 | SankeyChart | Visual |
48
+ | 퍼널 차트 | FunnelChart | Visual |
49
+ | 리텐션 히트맵 | RetentionHeatmap | Visual |
50
+ | 캘린더 히트맵 | CalendarHeatmap | Visual |
51
+ | 폭포 차트 | WaterfallChart | Visual |
52
+ | 버블 차트 | BubbleChart | Visual |
53
+ | 게이지/미터 | GaugeChart | Visual |
54
+ | KPI/통계 카드 | StatCard (Core) / MetricsCard / SummaryRow (Shell) | Core / Shell |
55
+ | 모달 대화상자 | Dialog | Core |
56
+ | 확인 대화상자 | ConfirmDialog | Shell |
57
+ | 서랍 패널 | Drawer | Core |
58
+ | 팝오버 | Popover | Core |
59
+ | 드롭다운 메뉴 | DropdownMenu | Core |
60
+ | 토스트 알림 | NotificationToast | Shell |
61
+ | 알림 센터 | NotificationCenter | Shell |
62
+ | 사이드바 내비게이션 | SidebarNav / Sidebar | Shell |
63
+ | 앱 레이아웃 | AppShell | Shell |
64
+ | 탭 내비게이션 | Tabs (Core) / ContentTabs / VerticalTabs (Shell) | Core / Shell |
65
+ | 메뉴 | Menu (Core) / AppMenubar / MegaMenu (Shell) | Core / Shell |
66
+ | 커맨드 팔레트 | CommandPalette | Shell |
67
+ | 아코디언 | Disclosure (Core) / FaqAccordion (Shell) | Core / Shell |
68
+ | 설정 폼 | SettingsForm | Shell |
69
+ | 로그인 폼 | AuthForm | Shell |
70
+ | 다단계 폼 | WizardForm | Shell |
71
+ | 동적 필드 폼 | DynamicFieldForm | Shell |
72
+ | 파일 업로드 폼 | FileUploadForm | Shell |
73
+ | SQL 에디터 | SqlEditor | Shell |
74
+ | 코드 표시 | CodeSnippetViewer | Shell |
75
+ | 코드 비교 | CodeDiffViewer | Shell |
76
+ | 리치 텍스트 에디터 | RichTextEditor | Shell |
77
+ | 단계 빌더 | StepBuilder | Core |
78
+ | 조건 빌더 | ConditionBuilder | Core |
79
+ | 경로 탐색 | Breadcrumb | Core |
80
+ | 빈 상태 표시 | EmptyState | Core |
81
+ | 로딩 스피너 | Spinner / LoadingOverlay | Core |
82
+ | 프로그레스 바 | Progress | Core |
83
+ | 아바타 | Avatar | Core |
84
+ | 페이지네이션 | Pagination | Core |
85
+ | 가상 목록 | VirtualList | Core |
86
+ | 리사이즈 패널 | Resizable | Core |
87
+ | 페이지 헤더 | PageHeader | Core |
88
+ | 테마 전환 | ThemeSwitcher | Shell |
89
+ | 데이터 내보내기 | ExportButton | Shell |
90
+ | 데이터 임포트 | DataImportWizard | Shell |
91
+ | 웹훅 설정 | WebhookConfig | Shell |
92
+ | 피처 플래그 | FeatureFlagPanel | Shell |
93
+ | 감사 로그 | AuditLog | Shell |
94
+ | 워크플로우 에디터 | WorkflowCanvas | Shell |
95
+ | 인사이트/이상탐지 | InsightsPanel | Shell |
96
+ | 프롬프트 템플릿 | PromptTemplate | Shell |
97
+
98
+ ## Core Components (59)
99
+
100
+ ### Input
101
+
102
+ | Component | Description | Key Exports |
103
+ | --------------- | -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
104
+ | Input | 독립적인 텍스트 입력 컴포넌트. 레이블, 에러, 힌트, 아이콘 지원. | `Input` |
105
+ | Textarea | 멀티라인 텍스트 입력. Input과 동일한 API (label, error, hint). | `Textarea` |
106
+ | NumberInput | 숫자 입력 컴포넌트. +/- 버튼, nullable/clear, unit suffix, invalid draft alert, min/max, step, 키보드 화살표를 지원합니다. | `NumberInput` |
107
+ | Checkbox | 독립적인 체크박스 컴포넌트. 레이블, 설명, 그룹과 DOM property까지 동기화되는 indeterminate 상태를 지원합니다. | `Checkbox`, `CheckboxGroup` |
108
+ | RadioGroup | 독립적인 라디오 그룹 컴포넌트. 그룹 설명과 항목별 설명을 분리 연결하고 다양한 크기를 지원합니다. | `RadioGroup`, `Radio` |
109
+ | Switch | 토글 스위치 컴포넌트. 3가지 크기와 레이블/설명의 명시적 접근성 연결을 지원합니다. | `Switch` |
110
+ | Select | 드롭다운 선택 컴포넌트. 5-part anatomy: Root, Label, Trigger, Popover, Item. | `SelectRoot`, `SelectLabel`, `SelectTrigger`, `SelectPopover`, `SelectItem` |
111
+ | Combobox | 자동완성 검색 입력. 7 exports: Root, Input, Popover, Item, Group, GroupLabel, Empty. | `ComboboxRoot`, `ComboboxInput`, `ComboboxPopover`, `ComboboxItem`, `ComboboxGroup`, `ComboboxGroupLabel`, `ComboboxEmpty` |
112
+ | DateRangePicker | 날짜 범위 선택 컴포넌트. 프리셋, 달력 UI, 포커스 관리와 RTL 방향 탐색 아이콘을 지원합니다. | `DateRangePicker` |
113
+ | TagInput | 태그 입력 컴포넌트. 텍스트를 입력하고 Enter로 태그를 추가, Backspace로 삭제합니다. | `TagInput` |
114
+ | ColorPicker | 색상 선택 컴포넌트. 프리셋 팔레트와 hex 입력을 지원합니다. | `ColorPicker` |
115
+ | IconPicker | 아이콘 선택 컴포넌트. 검색, 그룹별 분류, semantic key 기반 Lucide 아이콘과 커스텀 ReactNode를 지원합니다. | `IconPicker` |
116
+ | Slider | 범위 슬라이더 입력. native range input 래핑, 범위로 정규화된 값/ARIA 상태, 값 표시와 포맷 함수를 지원합니다. | `Slider` |
117
+
118
+ ### Form Integration
119
+
120
+ | Component | Description | Key Exports |
121
+ | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
122
+ | Form | 접근성 폼 시스템. opt-ui-primitives Form API 기반. 31 exports: FormRoot, FormProvider, FormGroup, FormGroupLabel, FormDescription, FormField, FormControl, FormInput, FormTextarea, FormSelect, FormSelectPopover, FormSelectItem, FormSwitch, FormLabel, FormError, FormSubmit, FormCheckbox, FormRadioGroup, FormRadio, FormPush, FormRemove, FormReset, FormNumberInput, FormSlider, FormStarRating, FormColorPicker, FormIconPicker, FormTagInput, FormDateRangePicker + useFormStore, useFormContext hooks. | `FormRoot`, `FormProvider`, `FormGroup`, `FormGroupLabel`, `FormDescription`, `FormField`, `FormControl`, `FormInput`, `FormTextarea`, `FormSelect`, `FormSelectPopover`, `FormSelectItem`, `FormSwitch`, `FormLabel`, `FormError`, `FormSubmit`, `FormCheckbox`, `FormRadioGroup`, `FormRadio`, `FormPush`, `FormRemove`, `FormReset`, `FormNumberInput`, `FormSlider`, `FormStarRating`, `FormColorPicker`, `FormIconPicker`, `FormTagInput`, `FormDateRangePicker`, `useFormStore`, `useFormContext` |
123
+
124
+ ### Display
125
+
126
+ | Component | Description | Key Exports |
127
+ | -------------- | --------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- |
128
+ | Kbd | 키보드 단축키를 시각적으로 표시하는 인라인 뱃지 컴포넌트. | `Kbd` |
129
+ | Button | 접근성 버튼 컴포넌트. 4가지 변형(primary, secondary, ghost, danger), 3가지 크기, 로딩/아이콘과 aria-busy 상태를 지원합니다. | `Button` |
130
+ | Badge | 인라인 상태 뱃지. 5가지 색상 변형, 상태 점(dot) 옵션 지원. | `Badge` |
131
+ | Alert | 알림 메시지 컴포넌트. 4가지 변형(info, success, warning, error), 제목/본문/닫기 버튼 지원. | `Alert` |
132
+ | Spinner | 로딩 상태 표시 스피너. 3가지 크기와 장식용 aria-hidden 모드를 지원합니다. | `Spinner` |
133
+ | LoadingOverlay | 로딩 오버레이. 중복 status 없이 하나의 aria-busy 라이브 영역으로 콘텐츠 위 로딩 상태를 표시합니다. | `LoadingOverlay` |
134
+ | Progress | 진행률 표시. Linear/Circular, determinate/indeterminate 변형과 안전하게 보정된 ARIA 값을 지원합니다. | `Progress`, `CircularProgress` |
135
+ | Avatar | 사용자 아바타. 이미지, 이니셜 자동 생성, 스크린 리더에 노출되는 상태 인디케이터, 그룹을 지원합니다. | `Avatar`, `AvatarGroup` |
136
+ | Skeleton | 로딩 플레이스홀더. text/circular/rectangular 변형. 프리셋 컴포넌트 포함. | `Skeleton`, `SkeletonText`, `SkeletonAvatar`, `SkeletonCard`, `SkeletonTable` |
137
+ | Card | 범용 카드 컨테이너. Header, Title, Description, Content, Footer 하위 컴포넌트 포함. | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter` |
138
+ | Breadcrumb | 현재 위치를 표시하고 계층 탐색을 제공하는 컴포넌트. | `Breadcrumb` |
139
+ | EmptyState | 데이터가 없을 때 표시하는 빈 상태 컴포넌트. 아이콘, 제목, 설명, 액션 버튼 지원. | `EmptyState` |
140
+ | StatCard | 트렌드 방향과 변화량을 표시하는 통계 카드. | `StatCard` |
141
+ | Logo | 아이콘+텍스트 조합, 이미지, 링크 래핑을 지원하는 로고 컴포넌트. Sidebar 등에서 활용. | `Logo` |
142
+
143
+ ### Navigation & Overlay
144
+
145
+ | Component | Description | Key Exports |
146
+ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
147
+ | Menu | 메뉴바 + 개별 메뉴 시스템. 10 exports: MenubarRoot, MenubarContainer, MenuRoot, MenuTrigger, MenuButtonArrow, MenuPopover, MenuItem, MenuItemCheckbox, MenuItemRadio, MenuSeparator. | `MenubarRoot`, `MenubarContainer`, `MenuRoot`, `MenuTrigger`, `MenuButtonArrow`, `MenuPopover`, `MenuItem`, `MenuItemCheckbox`, `MenuItemRadio`, `MenuSeparator` |
148
+ | DropdownMenu | Menu Core 위의 간편 래퍼. 단일 트리거 드롭다운 메뉴에 특화되었습니다. | `DropdownMenu`, `DropdownTrigger`, `DropdownContent`, `DropdownItem`, `DropdownSeparator` |
149
+ | Popover | Popover 프리미티브 래퍼. 트리거 요소에 연결된 플로팅 콘텐츠를 표시합니다. | `PopoverRoot`, `PopoverTrigger`, `PopoverContent`, `PopoverClose` |
150
+ | Tabs | 탭 패널 시스템. 4-part anatomy: Root, TabList, Tab, TabPanel. | `TabsRoot`, `TabList`, `Tab`, `TabPanel` |
151
+ | Disclosure | 접기/펼치기 콘텐츠 영역. 3-part anatomy: Root, Trigger, Content. | `DisclosureRoot`, `DisclosureTrigger`, `DisclosureContent` |
152
+ | Dialog | 모달 다이얼로그. 9-part anatomy: Root, Disclosure, Panel, Heading, Description, Dismiss, Header, Body, Footer. | `DialogRoot`, `DialogDisclosure`, `DialogPanel`, `AlertDialogPanel`, `DialogHeading`, `DialogDescription`, `DialogDismiss`, `DialogHeader`, `DialogBody`, `DialogFooter` |
153
+ | Drawer | 사이드/하단 슬라이드 패널. Dialog 기반 compound 패턴으로 접근성을 보장합니다. | `DrawerRoot`, `DrawerPanel`, `DrawerClose` |
154
+ | Toolbar | 툴바 컨테이너 + 툴팁. 7 exports: ToolbarRoot, ToolbarContainer, ToolbarButton, ToolbarSeparator, TooltipProvider, TooltipAnchor, Tooltip. | `ToolbarRoot`, `ToolbarContainer`, `ToolbarButton`, `ToolbarSeparator`, `TooltipProvider`, `TooltipAnchor`, `Tooltip` |
155
+ | Pagination | 페이지 넘김 네비게이션. ellipsis 포함 페이지 번호, compact/count variant, totalPages/cursor pagination, Prev/Next 버튼을 제공합니다. | `Pagination` |
156
+
157
+ ### Layout
158
+
159
+ | Component | Description | Key Exports |
160
+ | ------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------- |
161
+ | CompositeZone | Composite 기반 2D 키보드 탐색 컨테이너. 화살표 키로 자식 요소 간 이동 가능. | `CompositeZone` |
162
+ | PageHeader | 페이지 제목, 설명, 액션 슬롯을 제공하는 레이아웃 헤더 컴포넌트. | `PageHeader` |
163
+ | ScrollArea | 커스텀 스크롤바를 제공하는 스크롤 컨테이너. 수직/수평/양방향 지원. | `ScrollArea` |
164
+ | Container | 최대 너비 제약과 중앙 정렬을 제공하는 래퍼. 페이지 콘텐츠 폭 제한용. | `Container` |
165
+ | Section | 시맨틱 스페이싱 블록. 제목이 있으면 aria-labelledby를 자동 설정합니다. | `Section` |
166
+ | Resizable | react-resizable-panels 래퍼. 드래그로 크기를 조절할 수 있는 패널 분할 레이아웃. | `ResizablePanelGroup`, `ResizablePanel`, `ResizableHandle` |
167
+ | VirtualList | 가상 스크롤 리스트. 대량 데이터를 윈도잉 기법으로 효율적으로 렌더링합니다. | `VirtualList` |
168
+
169
+ ### Builder
170
+
171
+ | Component | Description | Key Exports |
172
+ | ---------------- | ------------------------------------------------------------------------- | ------------------ |
173
+ | StepBuilder | 순서가 있는 단계를 추가, 제거, 재정렬할 수 있는 빌더 컴포넌트. | `StepBuilder` |
174
+ | ConditionBuilder | AND/OR 로직으로 조건 그룹을 구성하는 빌더. 속성, 연산자, 값을 조합합니다. | `ConditionBuilder` |
175
+
176
+ ### Other
177
+
178
+ | Component | Description | Key Exports |
179
+ | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
180
+ | Text | 본문, 레이블, 보조 설명, 코드에 일관된 의미 기반 타이포그래피를 적용합니다. | `Text` |
181
+ | Heading | 문서의 의미 계층과 시각적 타이포그래피 계층을 독립적으로 제어합니다. | `Heading` |
182
+ | Separator | 콘텐츠를 구분하는 가로/세로 디바이더. 라벨을 넣으면 가운데 정렬 구분선이 된다. | `Separator` |
183
+ | OtpField | 일회용 코드(OTP)/PIN 입력. 셀 단위 입력, 붙여넣기 분배, 자동 포커스 이동, 백스페이스 네비게이션과 폼 이름/오류 연결을 지원합니다. | `OtpField` |
184
+ | Toggle | 눌림(pressed) 두 상태 버튼. 단독 사용하거나 ToggleGroup으로 묶어 단일/다중 선택을 만든다. | `Toggle`, `ToggleGroup` |
185
+ | Accordion | 수직으로 쌓인 펼침/접힘 패널. single(한 개)/multiple(여러 개) 모드와 collapsible 지원. | `AccordionRoot`, `AccordionItem`, `AccordionTrigger`, `AccordionContent` |
186
+ | Meter | 범위 내 스칼라 측정값 게이지 (디스크 사용량·점수·용량 등). role=meter로 작업 진행률(Progress)과 구분된다. | `Meter` |
187
+ | BlockLayout | Block 루트 레이아웃. flex + 기본 section spacing 적용, loading prop으로 LoadingOverlay 자동 래핑. | `BlockLayout` |
188
+ | createBlock | Block 팩토리 함수. BlockLayout 래핑을 구조적으로 강제하여 loading/className 처리를 자동화합니다. | `createBlock` |
189
+ | StarRating | 1~N점 별점을 선택하는 인터랙티브 레이팅 입력. 읽기 전용 표시도 지원. | `StarRating` |
190
+ | ErrorBoundary | React 에러 바운더리. 자식 컴포넌트 렌더 에러를 잡아 fallback UI를 표시합니다. | `ErrorBoundary` |
191
+ | Command | cmdk 스타일 명령 anatomy. 자동 필터링 + 키보드 내비게이션. 인라인 또는 CommandDialog로 사용. | `Command`, `CommandDialog`, `CommandInput`, `CommandList`, `CommandEmpty`, `CommandGroup`, `CommandItem`, `CommandSeparator`, `CommandShortcut` |
192
+ | ShaderSurface | ogl 기반 애니메이션 WebGL 셰이더 배경. 럭셔리 프리셋(메탈릭/실크/유리 등) + 색·파라미터로 배경·카드 배경을 만든다. 정지 프레임·PNG 캡처·WebGL 폴백 지원. | `ShaderSurface` |
193
+
194
+ ## Visual Components (0)
195
+
196
+ | Component | Description | Key Exports |
197
+ | --------- | ----------- | ----------- |
198
+
199
+ ## Shell Components (75)
200
+
201
+ ### Navigation & Layout
202
+
203
+ | Component | Description | Key Exports |
204
+ | --------------------- | --------------------------------------------------------------------------------------------------------------------- | ----------------------- |
205
+ | AppMenubar | 데스크톱 스타일 메뉴바. 체크박스, 라디오 메뉴 항목 지원. | `AppMenubar` |
206
+ | MegaMenu | 메가 메뉴. Popover + CSS grid 멀티컬럼 + 카테고리 헤딩 + footer 슬롯. | `MegaMenu` |
207
+ | SidebarNav | Composite 기반 사이드바 네비게이션. pathname 자동 동기화. | `SidebarNav` |
208
+ | Sidebar | 접기/펼치기를 지원하는 compound 사이드바. Header/Content/Footer 구조 + Group/Item으로 네비게이션 구성. Ctrl+[ 단축키. | `Sidebar`, `useSidebar` |
209
+ | AppShell | Header + Sidebar + Content + Footer 4영역 페이지 레이아웃 템플릿. Sidebar 컴포넌트와 조합. | `AppShell` |
210
+ | ContentTabs | 탭 콘텐츠 패널. Tabs primitive 래퍼. | `ContentTabs` |
211
+ | VerticalTabs | 세로 탭 레이아웃. 좌측 탭 리스트 + 우측 패널 구성입니다. | `VerticalTabs` |
212
+ | FaqAccordion | FAQ 질문/답변 아코디언. Composite + Disclosure 조합. | `FaqAccordion` |
213
+ | CommandPalette | Cmd+K 스타일 커맨드 팔레트. Dialog + Combobox + match-sorter 퍼지 검색. | `CommandPalette` |
214
+ | CommandPaletteTrigger | CommandPalette + Cmd+K 키보드 단축키 자동 바인딩. | `CommandPaletteTrigger` |
215
+ | ProjectSwitcher | 프로젝트 검색 전환기. Combobox + match-sorter 퍼지 검색 지원. | `ProjectSwitcher` |
216
+ | EditorToolbar | 리치 텍스트 에디터 스타일 툴바. Toolbar + Tooltip 조합. | `EditorToolbar` |
217
+ | FloatingActionBar | 플로팅 액션 바. 선택된 항목에 대한 일괄 작업 버튼을 하단에 표시합니다. | `FloatingActionBar` |
218
+ | TemplatePicker | 템플릿 선택기. 카테고리별 그리드와 검색을 제공하며 featured/tags 표시를 지원합니다. | `TemplatePicker` |
219
+ | ThemeSwitcher | 테마 프리셋 선택기. 프리셋과 light/dark/system 모드 전환. | `ThemeSwitcher` |
220
+
221
+ ### Data Display
222
+
223
+ | Component | Description | Key Exports |
224
+ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- |
225
+ | DataTable | 제네릭 데이터 테이블. 동적 컬럼, 결측값 안전 정렬, 키보드 컬럼 리사이즈, 보정된 인라인 진행률과 Composite 탐색을 지원합니다. | `DataTable` |
226
+ | InlineEditTable | 인라인 편집 테이블. 더블클릭으로 셀 편집, Enter 확정, Escape 취소. | `InlineEditTable` |
227
+ | TreeTable | 계층형 트리 테이블. 재귀 행 렌더링 + 펼침/접기 셰브론. | `TreeTable` |
228
+ | DomainTable | 도메인 테이블. Composite 기반 그리드로 키보드 탐색 지원. | `DomainTable` |
229
+ | QueryResultsTable | 쿼리 결과 테이블. SQL 결과와 스크린 리더에 안내되는 로딩, 에러, 빈 상태를 지원합니다. | `QueryResultsTable` |
230
+ | DashboardGrid | Composite 기반 통계 카드 그리드. 유효한 1–4열 레이아웃과 화살표 키 2D 탐색을 지원합니다. | `DashboardGrid` |
231
+ | SummaryRow | 통계 요약 행. StatCard 그리드 레이아웃을 표준화합니다. loading 시 SkeletonCard 표시. | `SummaryRow` |
232
+ | CodeSnippetViewer | 코드 스니펫 뷰어. 줄 번호, 복사 버튼, 포커스 가능한 스크롤 영역, syntaxTheme 톤을 지원합니다. | `CodeSnippetViewer` |
233
+ | CodeDiffViewer | 코드 비교 뷰어. LCS 알고리즘 기반 unified/split 모드 diff와 포커스 가능한 스크롤 영역을 제공합니다. | `CodeDiffViewer` |
234
+ | ConnectionIndicator | 연결 상태 표시기. connected, connecting, disconnected, error 상태를 지원합니다. | `ConnectionIndicator` |
235
+ | EventIcon | 이벤트 아이콘. semantic key 또는 ReactNode 아이콘과 배경색을 표시합니다. | `EventIcon`, `POPULAR_ICONS`, `COLOR_PRESETS` |
236
+
237
+ ### Lists & Feeds
238
+
239
+ | Component | Description | Key Exports |
240
+ | ------------------ | ----------------------------------------------------------------------------------- | -------------------- |
241
+ | TaskList | 작업 목록 관리 컴포넌트. 우선순위, 상태, 담당자, 태그, 하위 작업 지원. | `TaskList` |
242
+ | ActivityFeed | 활동 피드/로그 컴포넌트. 타임라인 스타일, 상대 시간 표시. | `ActivityFeed` |
243
+ | TeamMemberList | 팀원 목록 컴포넌트. 온라인 상태, 다양한 레이아웃(list, compact, avatars-only) 지원. | `TeamMemberList` |
244
+ | KanbanBoard | 칸반 보드. HTML5 DnD로 카드를 컬럼 간 드래그&드롭. | `KanbanBoard` |
245
+ | AuditLog | 감사 로그 타임라인. 아바타 + 액션 텍스트 + 메타데이터 배지 레이아웃. | `AuditLog` |
246
+ | NotificationCenter | 알림 센터. 벨 아이콘 트리거 + 미읽음 배지 + 스크롤 알림 목록. | `NotificationCenter` |
247
+
248
+ ### Filters & Search
249
+
250
+ | Component | Description | Key Exports |
251
+ | ------------------ | ------------------------------------------------------------------------------------------------------------------ | -------------------- |
252
+ | SearchCombobox | match-sorter 기반 퍼지 검색 콤보박스. | `SearchCombobox` |
253
+ | AsyncCombobox | 비동기 검색 콤보박스. 디바운스 + 로딩 스피너와 stale response 방어를 내장합니다. | `AsyncCombobox` |
254
+ | StatusSelect | 색상 인디케이터가 있는 상태 선택 드롭다운. | `StatusSelect` |
255
+ | BranchSelect | Git 브랜치 선택 드롭다운. Select primitive 래퍼. | `BranchSelect` |
256
+ | FilterBar | 필터링 바 컴포넌트. 검색, 선택, 다중 선택 필터 지원. | `FilterBar` |
257
+ | SavedFilters | 필터 프리셋 관리. 현재 필터를 저장하고 불러오는 Popover UI. | `SavedFilters` |
258
+ | QuickActions | 빠른 작업 패널. 그리드/리스트 레이아웃, 단축키 표시 지원. | `QuickActions` |
259
+ | TimeRangeSelector | 시간 범위 선택기. Popover + DateRangePicker + 프리셋 버튼 조합. 12개 시계열 Surface에서 사용. | `TimeRangeSelector` |
260
+ | ComparisonSelector | 비교 선택기. 고유 레이블이 연결된 Select × 2 + Swap 버튼 조합. CohortComparison, FunnelAnalysis 등에서 사용합니다. | `ComparisonSelector` |
261
+ | ColumnToggler | 테이블 컬럼 표시/숨김 토글러. Popover + Checkbox 리스트입니다. | `ColumnToggler` |
262
+ | BulkActions | 일괄 작업 바. 선택 카운트 배지 + DropdownMenu 액션 목록 + 해제 버튼. | `BulkActions` |
263
+
264
+ ### Forms
265
+
266
+ | Component | Description | Key Exports |
267
+ | ---------------- | ---------------------------------------------------------------------------------------------------------------------- | ------------------ |
268
+ | SettingsForm | 데이터 기반 설정 폼. 유효성 검증, 라디오, 체크박스 지원. | `SettingsForm` |
269
+ | AuthForm | 로그인/회원가입 모드 전환 가능한 인증 폼. 이메일·비밀번호 검증, FormSwitch로 로그인 상태 유지 옵션 지원. | `AuthForm` |
270
+ | DynamicFieldForm | 런타임 필드 추가/제거 폼. 최소/최대 필드 수 제약, 개별 검증, 동적 스토어 업데이트 지원. | `DynamicFieldForm` |
271
+ | FileUploadForm | 파일 선택, 메타데이터 표시, 이미지 미리보기를 포함한 업로드 폼. 파일 크기 제한, 설명 입력 지원. | `FileUploadForm` |
272
+ | WizardForm | 다단계 순차 입력 폼. FormFieldDef 기반 필드 정의, 단계별 검증, 현재 단계가 연결된 진행 표시기, 리뷰 단계를 지원합니다. | `WizardForm` |
273
+ | ConfirmDialog | 확인/취소 대화 상자. danger 변형으로 위험 작업 확인을 지원합니다. | `ConfirmDialog` |
274
+ | PromptTemplate | AI 프롬프트 뷰어/헬퍼. 변수 입력 → 실시간 치환 → 복사 기능. | `PromptTemplate` |
275
+
276
+ ### Infrastructure
277
+
278
+ | Component | Description | Key Exports |
279
+ | ------------------ | --------------------------------------------------------------------------- | -------------------- |
280
+ | DeploymentTimeline | 배포 단계 타임라인. Composite 기반 키보드 탐색 지원. | `DeploymentTimeline` |
281
+ | EnvPanel | 환경변수 패널. Disclosure로 환경별 그룹 접기/펼치기, Composite로 변수 탐색. | `EnvPanel` |
282
+ | WebhookConfig | 웹훅 설정 패널. URL 입력 + 이벤트 체크박스 + 재시도 설정 + 테스트 버튼. | `WebhookConfig` |
283
+ | FeatureFlagPanel | 피처 플래그 관리 패널. 플래그 토글 + 환경 배지 + 롤아웃 % 조절. | `FeatureFlagPanel` |
284
+ | DataImportWizard | 데이터 임포트 마법사. 4단계: 업로드 → 컬럼 매핑 → 미리보기 → 확인. | `DataImportWizard` |
285
+
286
+ ### Analytics
287
+
288
+ | Component | Description | Key Exports |
289
+ | ---------------- | ---------------------------------------------------------------------------------------------------------------- | ------------------ |
290
+ | SqlEditor | SQL 에디터. CodeMirror 기반의 SQL 편집기로 구문 강조와 자동 완성을 지원합니다. | `SqlEditor` |
291
+ | EventMetaEditor | 이벤트 메타 에디터. 레이블이 연결된 IconPicker + ColorPicker + TagInput 조합으로 이벤트 메타데이터를 편집합니다. | `EventMetaEditor` |
292
+ | PropertyExplorer | 프로퍼티 탐색기. 검색 가능한 속성 목록을 그룹별로 표시합니다. | `PropertyExplorer` |
293
+ | RichTextEditor | 마크다운 리치 텍스트 에디터. 서식 툴바 + textarea 조합. | `RichTextEditor` |
294
+ | ExportButton | 데이터 내보내기 버튼. CSV/JSON 변환 내장, PDF는 콜백 위임. DropdownMenu 기반. | `ExportButton` |
295
+ | InsightsPanel | 이상 탐지 인사이트 패널. severity별 카드, 통계 필터, dismiss 기능, 검출 설정(유형/Z-score/days). | `InsightsPanel` |
296
+
297
+ ### Builders
298
+
299
+ | Component | Description | Key Exports |
300
+ | -------------- | ------------------------------------------------------------------------------------------------------------------ | ---------------- |
301
+ | AlertBuilder | 알림 빌더. 명시적으로 연결된 폼 레이블로 메트릭 조건, 빈도, 채널을 구성합니다. | `AlertBuilder` |
302
+ | SegmentBuilder | 세그먼트 빌더. 각 조건 컨트롤의 접근 가능한 이름을 유지하며 event, property, cohort, custom 세그먼트를 정의합니다. | `SegmentBuilder` |
303
+ | ReportBuilder | 리포트 빌더. 레이블이 연결된 4단계 위저드 (차트 타입 → 데이터 설정 → 스타일 → 미리보기). | `ReportBuilder` |
304
+
305
+ ### Widgets & Reports
306
+
307
+ | Component | Description | Key Exports |
308
+ | ---------- | ---------------------------------------------------------------------------------------- | ------------ |
309
+ | WidgetGrid | 위젯 그리드. react-grid-layout 래퍼로 드래그/리사이즈 가능한 대시보드 위젯을 배치합니다. | `WidgetGrid` |
310
+
311
+ ### Notification
312
+
313
+ | Component | Description | Key Exports |
314
+ | ----------------- | ------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
315
+ | NotificationToast | 토스트 알림 시스템. 포인터/키보드 상호작용 중 자동 닫힘을 일시 정지하고, 중요도별 live region으로 전역 알림을 관리합니다. | `ToastProvider`, `useToast`, `NotificationToast`, `toast` |
316
+
317
+ ### Development
318
+
319
+ | Component | Description | Key Exports |
320
+ | ---------------- | --------------------------------------------------------------------------------------------------- | ------------------ |
321
+ | DesignGuidePanel | 디자인 시스템 참조 패널. 프리미티브 맵, 키보드 패턴, Tailwind 셀렉터, 접근성 속성 등 6개 섹션 제공. | `DesignGuidePanel` |
322
+
323
+ ### Workflow
324
+
325
+ | Component | Description | Key Exports |
326
+ | -------------- | ---------------------------------------------------------------------------------- | ---------------- |
327
+ | WorkflowCanvas | 워크플로우 캔버스. 그리드 셀 기반 스텝 배치, SVG 연결선, 키보드 이동을 지원합니다. | `WorkflowCanvas` |
328
+
329
+ ### Other
330
+
331
+ | Component | Description | Key Exports |
332
+ | --------------- | -------------------------------------------------------------------------- | ----------------- |
333
+ | PageAside | Sticky 페이지 사이드 aside chrome. 고정 너비 + header/body/footer 3-slot. | `PageAside` |
334
+ | FailureList | 실패 목록 패널. severity별 색상 강조, 그룹핑, 액션 슬롯을 지원합니다. | `FailureList` |
335
+ | KeyValueEditor | 키-값 쌍 편집기. 동적 행 추가/삭제, 비밀값 토글, 유효성 검사를 지원합니다. | `KeyValueEditor` |
336
+ | AuditTimeline | 변경 이력 타임라인. 액션별 색상 코딩 + 확장 가능한 diff 뷰. | `AuditTimeline` |
337
+ | ChatSidebar | AI 채팅 사이드바. 대화 목록, 검색, 새 대화 버튼. | `ChatSidebar` |
338
+ | ChatInput | 채팅 입력 컴포넌트. 자동 리사이즈 textarea, 파일 첨부, 모델/스타일 Select. | `ChatInput` |
339
+ | ChatMessageList | 채팅 메시지 목록. 역할별 말풍선, 타이핑 인디케이터, 자동 스크롤. | `ChatMessageList` |
340
+
341
+ ## Surface Components (0)
342
+
343
+ | Surface | Description | Key Props | Dependencies |
344
+ | ------- | ----------- | --------- | ------------ |
345
+
346
+ ## Detailed Props Reference
347
+
348
+ ### Core Layer
349
+
350
+ #### Text
351
+
352
+ **Import:** `import { Text } from "@reopt-ai/opt-ui"`
353
+
354
+ | Prop | Type | Required | Default | Description |
355
+ | ---------- | ----------------------------------------------------- | -------- | ------- | --------------------- |
356
+ | `as` | `"span" \| "p" \| "div" \| "label" \| "code"` | | | 렌더링할 HTML 요소 |
357
+ | `variant` | `"body" \| "label" \| "supporting" \| "code"` | | | 시각적 텍스트 역할 |
358
+ | `tone` | `"primary" \| "secondary" \| "tertiary" \| "inherit"` | | | 의미 기반 텍스트 색상 |
359
+ | `truncate` | `boolean` | | | 한 줄 말줄임 적용 |
360
+ | `children` | `ReactNode` | | | 텍스트 콘텐츠 |
361
+
362
+ #### Heading
363
+
364
+ **Import:** `import { Heading } from "@reopt-ai/opt-ui"`
365
+
366
+ | Prop | Type | Required | Default | Description |
367
+ | ---------- | ------------------------------------------------------------------------ | -------- | ------- | ------------------------ |
368
+ | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | | | 의미 기반 HTML 제목 레벨 |
369
+ | `variant` | `"heading-1" … "heading-6" \| "display-1" \| "display-2" \| "display-3"` | | | 시각적 제목 역할 |
370
+ | `children` | `ReactNode` | | | 제목 콘텐츠 |
371
+
372
+ #### Kbd
373
+
374
+ **Import:** `import { Kbd } from "@reopt-ai/opt-ui"`
375
+
376
+ | Prop | Type | Required | Default | Description |
377
+ | ---------- | ----------- | -------- | ------- | -------------------- |
378
+ | `children` | `ReactNode` | Yes | | 표시할 단축키 텍스트 |
379
+
380
+ #### Separator
381
+
382
+ **Import:** `import { Separator } from "@reopt-ai/opt-ui"`
383
+
384
+ | Prop | Type | Required | Default | Description |
385
+ | ------------- | ---------------------------- | -------- | ------- | ------------------------------------- |
386
+ | `orientation` | `"horizontal" \| "vertical"` | | | 구분선 방향 (기본 horizontal) |
387
+ | `decorative` | `boolean` | | | 접근성 트리에서 숨김 (순수 시각 구분) |
388
+ | `children` | `ReactNode` | | | 가운데 라벨 (horizontal 전용) |
389
+ | `className` | `string` | | | 추가 CSS 클래스 |
390
+
391
+ #### OtpField
392
+
393
+ **Import:** `import { OtpField } from "@reopt-ai/opt-ui"`
394
+
395
+ | Prop | Type | Required | Default | Description |
396
+ | -------------- | ----------------------------- | -------- | ------- | ------------------------------------------- |
397
+ | `length` | `number` | | | 셀 개수 (기본 6) |
398
+ | `value` | `string` | | | 제어 모드 값 |
399
+ | `defaultValue` | `string` | | | 비제어 초기값 |
400
+ | `onChange` | `(value: string) => void` | | | 값 변경 콜백 |
401
+ | `onComplete` | `(value: string) => void` | | | 모든 셀이 채워지면 1회 호출 |
402
+ | `type` | `"numeric" \| "alphanumeric"` | | | 허용 문자 (기본 numeric) |
403
+ | `mask` | `boolean` | | | 채워진 셀을 점(•)으로 마스킹 (PIN 용) |
404
+ | `disabled` | `boolean` | | | 비활성화 |
405
+ | `name` | `string` | | | 폼 필드명. 전체 값을 담은 hidden input 렌더 |
406
+ | `label` | `string` | | | 필드 레이블 |
407
+ | `error` | `string` | | | 에러 메시지 |
408
+ | `hint` | `string` | | | 도움말 텍스트 |
409
+
410
+ #### Toggle
411
+
412
+ **Import:** `import { Toggle } from "@reopt-ai/opt-ui"`
413
+
414
+ **Toggle:**
415
+
416
+ | Prop | Type | Required | Default | Description |
417
+ | ----------------- | ---------------------------- | -------- | ------- | ---------------------------------------- |
418
+ | `pressed` | `boolean` | | | 제어 모드: 눌림 상태 (단독 사용) |
419
+ | `defaultPressed` | `boolean` | | | 비제어 초기 눌림 상태 (단독 사용) |
420
+ | `onPressedChange` | `(pressed: boolean) => void` | | | 눌림 상태 변경 콜백 (단독 사용) |
421
+ | `value` | `string` | | | ToggleGroup 내에서 이 토글을 식별하는 값 |
422
+ | `size` | `"sm" \| "md"` | | | 크기 (기본 md) |
423
+ | `disabled` | `boolean` | | | 비활성화 |
424
+ | `children` | `ReactNode` | | | 토글 콘텐츠 |
425
+
426
+ **ToggleGroup:**
427
+
428
+ | Prop | Type | Required | Default | Description |
429
+ | ---------------- | ------------------------------------- | -------- | ------- | ------------------------------------------------- |
430
+ | `value` | `string \| string[]` | | | 선택 값. 단일은 string, toggleMultiple은 string[] |
431
+ | `defaultValue` | `string \| string[]` | | | 비제어 초기 선택 값 |
432
+ | `onValueChange` | `(value: string \| string[]) => void` | | | 선택 변경 콜백 |
433
+ | `toggleMultiple` | `boolean` | | | 동시에 여러 개 눌림 허용 |
434
+ | `orientation` | `"horizontal" \| "vertical"` | | | 배치 방향 (기본 horizontal) |
435
+ | `disabled` | `boolean` | | | 그룹 전체 비활성화 |
436
+ | `children` | `ReactNode` | | | Toggle 항목들 |
437
+
438
+ #### Accordion
439
+
440
+ **Import:** `import { AccordionRoot } from "@reopt-ai/opt-ui"`
441
+
442
+ **AccordionRoot:**
443
+
444
+ | Prop | Type | Required | Default | Description |
445
+ | --------------- | --------------------------------------------- | -------- | ------- | ------------------------------------------------------------- |
446
+ | `type` | `"single" \| "multiple"` | | | 한 개만 열림(single) 또는 여러 개 열림(multiple). 기본 single |
447
+ | `value` | `string \| string[] \| null` | | | 열린 항목 값. single은 string\|null, multiple은 string[] |
448
+ | `defaultValue` | `string \| string[] \| null` | | | 비제어 초기 열림 값 |
449
+ | `onValueChange` | `(value: string \| string[] \| null) => void` | | | 열림 변경 콜백 |
450
+ | `collapsible` | `boolean` | | | single 모드에서 열린 패널을 다시 닫을 수 있게 허용 |
451
+ | `disabled` | `boolean` | | | 전체 비활성화 |
452
+ | `animated` | `boolean` | | | 콘텐츠 enter/leave 애니메이션 (기본 true) |
453
+ | `children` | `ReactNode` | | | AccordionItem 목록 |
454
+
455
+ **AccordionItem:**
456
+
457
+ | Prop | Type | Required | Default | Description |
458
+ | ---------- | ----------- | -------- | ------- | ------------------ |
459
+ | `value` | `string` | Yes | | 항목 식별 값 |
460
+ | `disabled` | `boolean` | | | 이 항목만 비활성화 |
461
+ | `children` | `ReactNode` | | | Trigger + Content |
462
+
463
+ **AccordionTrigger:**
464
+
465
+ | Prop | Type | Required | Default | Description |
466
+ | ---------- | ----------- | -------- | ------- | ----------------------------------- |
467
+ | `children` | `ReactNode` | Yes | | 헤더 라벨 (쉐브론 아이콘 자동 추가) |
468
+
469
+ **AccordionContent:**
470
+
471
+ | Prop | Type | Required | Default | Description |
472
+ | ---------- | ----------- | -------- | ------- | ------------------ |
473
+ | `children` | `ReactNode` | Yes | | 펼쳐지는 패널 본문 |
474
+
475
+ #### StatCard
476
+
477
+ **Import:** `import { StatCard } from "@reopt-ai/opt-ui"`
478
+
479
+ | Prop | Type | Required | Default | Description |
480
+ | -------- | ----------------------------- | -------- | ------- | ------------------------------- |
481
+ | `title` | `string` | Yes | | 통계 제목 |
482
+ | `value` | `string` | Yes | | 통계 값 |
483
+ | `change` | `string` | Yes | | 변화량 텍스트 (예: '+12.5%') |
484
+ | `trend` | `"up" \| "down" \| "neutral"` | Yes | | 트렌드 방향. 색상과 아이콘 결정 |
485
+
486
+ #### CompositeZone
487
+
488
+ **Import:** `import { CompositeZone } from "@reopt-ai/opt-ui"`
489
+
490
+ | Prop | Type | Required | Default | Description |
491
+ | ----------- | ----------- | -------- | ------- | --------------------------------- |
492
+ | `children` | `ReactNode` | Yes | | CompositeRow + CompositeItem 자식 |
493
+ | `label` | `string` | Yes | | aria-label 값 |
494
+ | `focusLoop` | `boolean` | | true | 포커스가 끝에서 처음으로 순환 |
495
+ | `focusWrap` | `boolean` | | true | 행 끝에서 다음 행으로 이동 |
496
+ | `className` | `string` | | | 컨테이너 CSS 클래스 |
497
+
498
+ #### Disclosure
499
+
500
+ **Import:** `import { DisclosureRoot } from "@reopt-ai/opt-ui"`
501
+
502
+ **DisclosureRoot:**
503
+
504
+ | Prop | Type | Required | Default | Description |
505
+ | ------------- | ------------------------- | -------- | ------- | --------------------------- |
506
+ | `open` | `boolean` | | | 제어 모드: 열림 상태 |
507
+ | `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 |
508
+ | `defaultOpen` | `boolean` | | false | 비제어 모드: 초기 열림 상태 |
509
+
510
+ **DisclosureTrigger:**
511
+
512
+ | Prop | Type | Required | Default | Description |
513
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
514
+ | `children` | `ReactNode` | Yes | | 트리거 내용 |
515
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
516
+
517
+ **DisclosureContent:**
518
+
519
+ | Prop | Type | Required | Default | Description |
520
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
521
+ | `children` | `ReactNode` | Yes | | 접히는 콘텐츠 |
522
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
523
+
524
+ #### Tabs
525
+
526
+ **Import:** `import { TabsRoot } from "@reopt-ai/opt-ui"`
527
+
528
+ **TabsRoot:**
529
+
530
+ | Prop | Type | Required | Default | Description |
531
+ | ------------------- | ------------------------------ | -------- | ------- | ------------------------- |
532
+ | `defaultSelectedId` | `string` | | | 초기 선택된 탭 ID |
533
+ | `selectedId` | `string \| null` | | | 제어 모드: 선택된 탭 ID |
534
+ | `setSelectedId` | `(id: string \| null) => void` | | | 제어 모드: 탭 변경 핸들러 |
535
+
536
+ **TabList:**
537
+
538
+ | Prop | Type | Required | Default | Description |
539
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
540
+ | `children` | `ReactNode` | Yes | | Tab 요소들 |
541
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
542
+
543
+ **Tab:**
544
+
545
+ | Prop | Type | Required | Default | Description |
546
+ | ----------- | ----------- | -------- | ------- | ------------------------------------ |
547
+ | `id` | `string` | Yes | | 탭 고유 ID (TabPanel의 tabId와 매칭) |
548
+ | `children` | `ReactNode` | Yes | | 탭 레이블 |
549
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
550
+
551
+ **TabPanel:**
552
+
553
+ | Prop | Type | Required | Default | Description |
554
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
555
+ | `tabId` | `string` | Yes | | 연결된 Tab의 ID |
556
+ | `children` | `ReactNode` | Yes | | 패널 콘텐츠 |
557
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
558
+
559
+ #### Select
560
+
561
+ **Import:** `import { SelectRoot } from "@reopt-ai/opt-ui"`
562
+
563
+ **SelectRoot:**
564
+
565
+ | Prop | Type | Required | Default | Description |
566
+ | --------------- | ------------------------------------- | -------- | ------- | -------------------------------------------------------- |
567
+ | `value` | `string \| string[]` | | | 제어 모드: 현재 선택 값 (multiple이면 string[]) |
568
+ | `onValueChange` | `(value: string \| string[]) => void` | | | 제어 모드: 값 변경 핸들러 |
569
+ | `defaultValue` | `string \| string[]` | | | 비제어 모드: 초기값 |
570
+ | `multiple` | `boolean` | | | 다중 선택 허용 (값이 string[]이 됨) |
571
+ | `name` | `string` | | | 폼 필드명. 선택값마다 hidden input을 렌더해 폼 전송 지원 |
572
+
573
+ **SelectLabel:**
574
+
575
+ | Prop | Type | Required | Default | Description |
576
+ | ---------- | ----------- | -------- | ------- | ------------- |
577
+ | `children` | `ReactNode` | Yes | | 레이블 텍스트 |
578
+
579
+ **SelectTrigger:**
580
+
581
+ | Prop | Type | Required | Default | Description |
582
+ | ----------- | ----------- | -------- | ------- | ---------------------------- |
583
+ | `children` | `ReactNode` | Yes | | 트리거 내용 (선택된 값 표시) |
584
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
585
+
586
+ **SelectPopover:**
587
+
588
+ | Prop | Type | Required | Default | Description |
589
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
590
+ | `children` | `ReactNode` | Yes | | SelectItem 목록 |
591
+ | `sameWidth` | `boolean` | | true | 트리거와 같은 너비 |
592
+ | `gutter` | `number` | | 4 | 트리거와의 간격 (px) |
593
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
594
+
595
+ **SelectItem:**
596
+
597
+ | Prop | Type | Required | Default | Description |
598
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
599
+ | `value` | `string` | Yes | | 옵션 값 |
600
+ | `children` | `ReactNode` | Yes | | 옵션 레이블 |
601
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
602
+
603
+ **Examples:**
604
+
605
+ _기본 선택:_
606
+
607
+ ```tsx
608
+ import {
609
+ SelectRoot,
610
+ SelectLabel,
611
+ SelectTrigger,
612
+ SelectPopover,
613
+ SelectItem,
614
+ } from "@reopt-ai/opt-ui";
615
+
616
+ <SelectRoot value={role} onValueChange={setRole}>
617
+ <SelectLabel>역할</SelectLabel>
618
+ <SelectTrigger>{role || "선택하세요"}</SelectTrigger>
619
+ <SelectPopover>
620
+ <SelectItem value="admin">관리자</SelectItem>
621
+ <SelectItem value="editor">편집자</SelectItem>
622
+ <SelectItem value="viewer">뷰어</SelectItem>
623
+ </SelectPopover>
624
+ </SelectRoot>;
625
+ ```
626
+
627
+ #### Dialog
628
+
629
+ **Import:** `import { DialogRoot } from "@reopt-ai/opt-ui"`
630
+
631
+ **DialogRoot:**
632
+
633
+ | Prop | Type | Required | Default | Description |
634
+ | --------- | ------------------------- | -------- | ------- | --------------------------- |
635
+ | `open` | `boolean` | | | 제어 모드: 열림 상태 |
636
+ | `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 |
637
+
638
+ **DialogDisclosure:**
639
+
640
+ | Prop | Type | Required | Default | Description |
641
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
642
+ | `children` | `ReactNode` | Yes | | 트리거 버튼 내용 |
643
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
644
+
645
+ **DialogPanel:**
646
+
647
+ | Prop | Type | Required | Default | Description |
648
+ | ----------- | ------------------------------------------------ | -------- | ------------------- | ---------------------- |
649
+ | `children` | `ReactNode` | Yes | | 다이얼로그 콘텐츠 |
650
+ | `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl" \| "full"` | | "md" | 최대 너비 프리셋 |
651
+ | `backdrop` | `ReactElement` | | <div> (반투명 배경) | 배경 오버레이 요소 |
652
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
653
+
654
+ **DialogHeading:**
655
+
656
+ | Prop | Type | Required | Default | Description |
657
+ | ---------- | ----------- | -------- | ------- | --------------------------------------- |
658
+ | `children` | `ReactNode` | Yes | | 제목 텍스트 (자동 aria-labelledby 연결) |
659
+
660
+ **DialogDescription:**
661
+
662
+ | Prop | Type | Required | Default | Description |
663
+ | ---------- | ----------- | -------- | ------- | ---------------------------------------- |
664
+ | `children` | `ReactNode` | Yes | | 설명 텍스트 (자동 aria-describedby 연결) |
665
+
666
+ **DialogDismiss:**
667
+
668
+ | Prop | Type | Required | Default | Description |
669
+ | ---------- | ----------- | -------- | ------- | -------------- |
670
+ | `children` | `ReactNode` | | | 닫기 버튼 내용 |
671
+
672
+ **DialogHeader:**
673
+
674
+ | Prop | Type | Required | Default | Description |
675
+ | ---------- | ----------- | -------- | ------- | -------------------------------------------- |
676
+ | `children` | `ReactNode` | Yes | | Heading, Description, Dismiss 등 헤더 콘텐츠 |
677
+
678
+ **DialogBody:**
679
+
680
+ | Prop | Type | Required | Default | Description |
681
+ | ---------- | ----------- | -------- | ------- | ------------------------- |
682
+ | `children` | `ReactNode` | Yes | | 스크롤 가능한 본문 콘텐츠 |
683
+
684
+ **DialogFooter:**
685
+
686
+ | Prop | Type | Required | Default | Description |
687
+ | ---------- | ----------- | -------- | ------- | -------------- |
688
+ | `children` | `ReactNode` | Yes | | 액션 버튼 영역 |
689
+
690
+ **Examples:**
691
+
692
+ _모달 대화상자:_
693
+
694
+ ```tsx
695
+ import {
696
+ DialogRoot,
697
+ DialogDisclosure,
698
+ DialogPanel,
699
+ DialogHeading,
700
+ DialogDismiss,
701
+ } from "@reopt-ai/opt-ui";
702
+
703
+ <DialogRoot>
704
+ <DialogDisclosure>열기</DialogDisclosure>
705
+ <DialogPanel size="md">
706
+ <DialogHeading>확인</DialogHeading>
707
+ <p>변경 사항을 저장하시겠습니까?</p>
708
+ <DialogDismiss>닫기</DialogDismiss>
709
+ </DialogPanel>
710
+ </DialogRoot>;
711
+ ```
712
+
713
+ #### Combobox
714
+
715
+ **Import:** `import { ComboboxRoot } from "@reopt-ai/opt-ui"`
716
+
717
+ **ComboboxRoot:**
718
+
719
+ | Prop | Type | Required | Default | Description |
720
+ | ------------------ | ------------------------- | -------- | ------- | -------------------------- |
721
+ | `setValue` | `(value: string) => void` | | | 입력값 변경 핸들러 |
722
+ | `resetValueOnHide` | `boolean` | | false | 팝오버 닫힐 때 입력값 리셋 |
723
+
724
+ **ComboboxInput:**
725
+
726
+ | Prop | Type | Required | Default | Description |
727
+ | ------------- | --------- | -------- | ------- | ---------------------- |
728
+ | `placeholder` | `string` | | | 플레이스홀더 텍스트 |
729
+ | `autoSelect` | `boolean` | | false | 첫 항목 자동 선택 |
730
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
731
+
732
+ **ComboboxPopover:**
733
+
734
+ | Prop | Type | Required | Default | Description |
735
+ | ----------- | ----------- | -------- | ------- | ----------------------- |
736
+ | `children` | `ReactNode` | Yes | | ComboboxItem/Group 목록 |
737
+ | `sameWidth` | `boolean` | | true | 입력과 같은 너비 |
738
+ | `gutter` | `number` | | 4 | 입력과의 간격 (px) |
739
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
740
+
741
+ **ComboboxItem:**
742
+
743
+ | Prop | Type | Required | Default | Description |
744
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
745
+ | `value` | `string` | Yes | | 항목 값 |
746
+ | `children` | `ReactNode` | Yes | | 항목 내용 |
747
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
748
+
749
+ **ComboboxGroup:**
750
+
751
+ | Prop | Type | Required | Default | Description |
752
+ | ---------- | ----------- | -------- | ------- | ---------------------- |
753
+ | `children` | `ReactNode` | Yes | | GroupLabel + Item 그룹 |
754
+
755
+ **ComboboxGroupLabel:**
756
+
757
+ | Prop | Type | Required | Default | Description |
758
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
759
+ | `children` | `ReactNode` | Yes | | 그룹 레이블 |
760
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
761
+
762
+ **ComboboxEmpty:**
763
+
764
+ | Prop | Type | Required | Default | Description |
765
+ | ----------- | ----------- | -------- | ------------------ | ---------------------- |
766
+ | `children` | `ReactNode` | | "결과가 없습니다." | 빈 상태 메시지 |
767
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
768
+
769
+ #### Menu
770
+
771
+ **Import:** `import { MenubarRoot } from "@reopt-ai/opt-ui"`
772
+
773
+ **MenubarRoot:**
774
+
775
+ | Prop | Type | Required | Default | Description |
776
+ | ---- | ---- | -------- | ------- | ----------- |
777
+
778
+ **MenubarContainer:**
779
+
780
+ | Prop | Type | Required | Default | Description |
781
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
782
+ | `children` | `ReactNode` | Yes | | MenuRoot 요소들 |
783
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
784
+
785
+ **MenuRoot:**
786
+
787
+ | Prop | Type | Required | Default | Description |
788
+ | ---- | ---- | -------- | ------- | ----------- |
789
+
790
+ **MenuTrigger:**
791
+
792
+ | Prop | Type | Required | Default | Description |
793
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
794
+ | `children` | `ReactNode` | Yes | | 메뉴 버튼 레이블 |
795
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
796
+
797
+ **MenuButtonArrow:**
798
+
799
+ | Prop | Type | Required | Default | Description |
800
+ | ----------- | -------- | -------- | ------- | ----------------- |
801
+ | `className` | `string` | | | 화살표 CSS 클래스 |
802
+
803
+ **MenuPopover:**
804
+
805
+ | Prop | Type | Required | Default | Description |
806
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
807
+ | `children` | `ReactNode` | Yes | | MenuItem 목록 |
808
+ | `gutter` | `number` | | 8 | 트리거와의 간격 (px) |
809
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
810
+
811
+ **MenuItem:**
812
+
813
+ | Prop | Type | Required | Default | Description |
814
+ | ----------- | ------------ | -------- | ------- | ---------------------- |
815
+ | `children` | `ReactNode` | Yes | | 메뉴 항목 내용 |
816
+ | `onClick` | `() => void` | | | 클릭 핸들러 |
817
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
818
+
819
+ **MenuItemCheckbox:**
820
+
821
+ | Prop | Type | Required | Default | Description |
822
+ | ----------- | -------------------------- | -------- | ------- | ---------------------- |
823
+ | `name` | `string` | Yes | | 체크박스 이름 |
824
+ | `value` | `string` | Yes | | 체크박스 값 |
825
+ | `checked` | `boolean` | | | 체크 상태 |
826
+ | `onChange` | `(e: ChangeEvent) => void` | | | 변경 핸들러 |
827
+ | `children` | `ReactNode` | Yes | | 항목 내용 |
828
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
829
+
830
+ **MenuItemRadio:**
831
+
832
+ | Prop | Type | Required | Default | Description |
833
+ | ----------- | -------------------------- | -------- | ------- | ---------------------- |
834
+ | `name` | `string` | Yes | | 라디오 그룹 이름 |
835
+ | `value` | `string` | Yes | | 라디오 값 |
836
+ | `checked` | `boolean` | | | 선택 상태 |
837
+ | `onChange` | `(e: ChangeEvent) => void` | | | 변경 핸들러 |
838
+ | `children` | `ReactNode` | Yes | | 항목 내용 |
839
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
840
+
841
+ **MenuSeparator:**
842
+
843
+ | Prop | Type | Required | Default | Description |
844
+ | ----------- | -------- | -------- | ------- | ---------------------- |
845
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
846
+
847
+ #### Toolbar
848
+
849
+ **Import:** `import { ToolbarRoot } from "@reopt-ai/opt-ui"`
850
+
851
+ **ToolbarRoot:**
852
+
853
+ | Prop | Type | Required | Default | Description |
854
+ | ----------- | --------- | -------- | ------- | ---------------- |
855
+ | `focusLoop` | `boolean` | | false | 포커스 순환 여부 |
856
+
857
+ **ToolbarContainer:**
858
+
859
+ | Prop | Type | Required | Default | Description |
860
+ | ----------- | ----------- | -------- | ------- | ------------------------------ |
861
+ | `children` | `ReactNode` | Yes | | ToolbarButton/Separator 요소들 |
862
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
863
+
864
+ **ToolbarButton:**
865
+
866
+ | Prop | Type | Required | Default | Description |
867
+ | ----------- | ------------ | -------- | ------- | ---------------------- |
868
+ | `children` | `ReactNode` | Yes | | 버튼 내용 |
869
+ | `onClick` | `() => void` | | | 클릭 핸들러 |
870
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
871
+
872
+ **ToolbarSeparator:**
873
+
874
+ | Prop | Type | Required | Default | Description |
875
+ | ----------- | -------- | -------- | ------- | ---------------------- |
876
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
877
+
878
+ **TooltipProvider:**
879
+
880
+ | Prop | Type | Required | Default | Description |
881
+ | ---- | ---- | -------- | ------- | ----------- |
882
+
883
+ **TooltipAnchor:**
884
+
885
+ | Prop | Type | Required | Default | Description |
886
+ | ---------- | -------------- | -------- | ------- | ------------------ |
887
+ | `render` | `ReactElement` | | | 앵커로 사용할 요소 |
888
+ | `children` | `ReactNode` | | | 앵커 내용 |
889
+
890
+ **Tooltip:**
891
+
892
+ | Prop | Type | Required | Default | Description |
893
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
894
+ | `children` | `ReactNode` | Yes | | 툴팁 내용 |
895
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
896
+
897
+ #### Form
898
+
899
+ **Import:** `import { FormRoot } from "@reopt-ai/opt-ui"`
900
+
901
+ **FormRoot:**
902
+
903
+ | Prop | Type | Required | Default | Description |
904
+ | ----------- | ----------- | -------- | ------- | ------------------------------------------------------------------------ |
905
+ | `store` | `FormStore` | | | useFormStore()로 생성한 폼 스토어. 미지정 시 자식의 FormProvider가 제공. |
906
+ | `children` | `ReactNode` | Yes | | 폼 필드들 |
907
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
908
+
909
+ **FormInput:**
910
+
911
+ | Prop | Type | Required | Default | Description |
912
+ | ------------- | -------- | -------- | ------- | ------------------------------- |
913
+ | `name` | `string` | Yes | | 폼 필드 이름 (스토어 키와 매칭) |
914
+ | `type` | `string` | | "text" | 입력 타입 |
915
+ | `placeholder` | `string` | | | 플레이스홀더 |
916
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
917
+
918
+ **FormTextarea:**
919
+
920
+ | Prop | Type | Required | Default | Description |
921
+ | ------------- | ------------------------------------------------ | -------- | ---------- | --------------- |
922
+ | `name` | `string` | Yes | | 폼 필드 이름 |
923
+ | `rows` | `number` | | 4 | 표시 줄 수 |
924
+ | `resize` | `"none" \| "vertical" \| "horizontal" \| "both"` | | "vertical" | 크기 조절 방향 |
925
+ | `placeholder` | `string` | | | 플레이스홀더 |
926
+ | `className` | `string` | | | 추가 CSS 클래스 |
927
+
928
+ **FormSelect:**
929
+
930
+ | Prop | Type | Required | Default | Description |
931
+ | ------------- | ----------- | -------- | ------- | ------------------------------ |
932
+ | `name` | `string` | Yes | | 폼 필드 이름 |
933
+ | `children` | `ReactNode` | Yes | | FormSelectPopover 등 자식 요소 |
934
+ | `placeholder` | `string` | | | 미선택 시 표시 텍스트 |
935
+ | `className` | `string` | | | 추가 CSS 클래스 |
936
+
937
+ **FormSelectPopover:**
938
+
939
+ | Prop | Type | Required | Default | Description |
940
+ | ----------- | ----------- | -------- | ------- | -------------------- |
941
+ | `children` | `ReactNode` | Yes | | FormSelectItem 목록 |
942
+ | `sameWidth` | `boolean` | | true | 트리거와 같은 너비 |
943
+ | `gutter` | `number` | | 4 | 트리거와의 간격 (px) |
944
+
945
+ **FormSelectItem:**
946
+
947
+ | Prop | Type | Required | Default | Description |
948
+ | ---------- | ----------- | -------- | ------- | ----------- |
949
+ | `value` | `string` | Yes | | 옵션 값 |
950
+ | `children` | `ReactNode` | Yes | | 옵션 레이블 |
951
+
952
+ **FormSwitch:**
953
+
954
+ | Prop | Type | Required | Default | Description |
955
+ | ---------- | ---------------------- | -------- | ------- | ------------- |
956
+ | `name` | `string` | Yes | | 폼 필드 이름 |
957
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 스위치 크기 |
958
+ | `disabled` | `boolean` | | | 비활성화 상태 |
959
+
960
+ **FormLabel:**
961
+
962
+ | Prop | Type | Required | Default | Description |
963
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
964
+ | `name` | `string` | Yes | | 연결된 필드 이름 |
965
+ | `children` | `ReactNode` | Yes | | 레이블 텍스트 |
966
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
967
+
968
+ **FormError:**
969
+
970
+ | Prop | Type | Required | Default | Description |
971
+ | ----------- | -------- | -------- | ------- | ---------------------- |
972
+ | `name` | `string` | Yes | | 연결된 필드 이름 |
973
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
974
+
975
+ **FormSubmit:**
976
+
977
+ | Prop | Type | Required | Default | Description |
978
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
979
+ | `children` | `ReactNode` | Yes | | 버튼 텍스트 |
980
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
981
+
982
+ **FormProvider:**
983
+
984
+ | Prop | Type | Required | Default | Description |
985
+ | ---------- | ----------- | -------- | ------- | --------------------------------- |
986
+ | `store` | `FormStore` | Yes | | useFormStore()로 생성한 폼 스토어 |
987
+ | `children` | `ReactNode` | Yes | | 자식 폼 요소 |
988
+
989
+ **FormGroup:**
990
+
991
+ | Prop | Type | Required | Default | Description |
992
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
993
+ | `children` | `ReactNode` | Yes | | 그룹 내 필드들 |
994
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
995
+
996
+ **FormGroupLabel:**
997
+
998
+ | Prop | Type | Required | Default | Description |
999
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
1000
+ | `children` | `ReactNode` | Yes | | 그룹 레이블 텍스트 |
1001
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1002
+
1003
+ **FormDescription:**
1004
+
1005
+ | Prop | Type | Required | Default | Description |
1006
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
1007
+ | `name` | `string` | Yes | | 연결된 필드 이름 |
1008
+ | `children` | `ReactNode` | Yes | | 도움말 텍스트 |
1009
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1010
+
1011
+ **FormField:**
1012
+
1013
+ | Prop | Type | Required | Default | Description |
1014
+ | ----------- | ----------- | -------- | ------- | ------------------------ |
1015
+ | `name` | `string` | Yes | | 필드 이름 |
1016
+ | `children` | `ReactNode` | Yes | | label + input + error 등 |
1017
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1018
+
1019
+ **FormControl:**
1020
+
1021
+ | Prop | Type | Required | Default | Description |
1022
+ | ----------- | -------- | -------- | ------- | ---------------------- |
1023
+ | `name` | `string` | Yes | | 연결된 필드 이름 |
1024
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1025
+
1026
+ **FormCheckbox:**
1027
+
1028
+ | Prop | Type | Required | Default | Description |
1029
+ | ----------- | -------- | -------- | ------- | ------------------------ |
1030
+ | `name` | `string` | Yes | | 폼 필드 이름 (스토어 키) |
1031
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1032
+
1033
+ **FormRadioGroup:**
1034
+
1035
+ | Prop | Type | Required | Default | Description |
1036
+ | ----------- | ----------- | -------- | ------- | ------------------------ |
1037
+ | `name` | `string` | Yes | | 폼 필드 이름 (스토어 키) |
1038
+ | `children` | `ReactNode` | Yes | | FormRadio 목록 |
1039
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1040
+
1041
+ **FormRadio:**
1042
+
1043
+ | Prop | Type | Required | Default | Description |
1044
+ | ----------- | -------- | -------- | ------- | ------------------------ |
1045
+ | `name` | `string` | Yes | | 폼 필드 이름 (스토어 키) |
1046
+ | `value` | `string` | Yes | | 라디오 값 |
1047
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1048
+
1049
+ **FormPush:**
1050
+
1051
+ | Prop | Type | Required | Default | Description |
1052
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
1053
+ | `name` | `string` | Yes | | 배열 필드 이름 |
1054
+ | `value` | `unknown` | Yes | | 추가할 기본값 |
1055
+ | `children` | `ReactNode` | Yes | | 버튼 텍스트 |
1056
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1057
+
1058
+ **FormRemove:**
1059
+
1060
+ | Prop | Type | Required | Default | Description |
1061
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
1062
+ | `name` | `string` | Yes | | 배열 필드 이름 |
1063
+ | `index` | `number` | Yes | | 제거할 인덱스 |
1064
+ | `children` | `ReactNode` | Yes | | 버튼 텍스트 |
1065
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1066
+
1067
+ **FormReset:**
1068
+
1069
+ | Prop | Type | Required | Default | Description |
1070
+ | ----------- | ----------- | -------- | ------- | ---------------------- |
1071
+ | `children` | `ReactNode` | Yes | | 버튼 텍스트 |
1072
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1073
+
1074
+ **useFormContext:**
1075
+
1076
+ | Prop | Type | Required | Default | Description |
1077
+ | ---- | ---- | -------- | ------- | ----------- |
1078
+
1079
+ **useFormStore:**
1080
+
1081
+ | Prop | Type | Required | Default | Description |
1082
+ | --------------- | ------------------------- | -------- | ------- | ----------- |
1083
+ | `defaultValues` | `Record<string, unknown>` | | | 초기 폼 값 |
1084
+
1085
+ **Examples:**
1086
+
1087
+ _기본 폼:_
1088
+
1089
+ ```tsx
1090
+ import {
1091
+ useFormStore,
1092
+ FormRoot,
1093
+ FormField,
1094
+ FormControl,
1095
+ FormLabel,
1096
+ FormError,
1097
+ FormSubmit,
1098
+ Input,
1099
+ } from "@reopt-ai/opt-ui";
1100
+
1101
+ const store = useFormStore({ defaultValues: { name: "", email: "" } });
1102
+
1103
+ <FormRoot store={store}>
1104
+ <FormField name="name">
1105
+ <FormLabel name="name">이름</FormLabel>
1106
+ <FormControl name="name">
1107
+ <Input />
1108
+ </FormControl>
1109
+ <FormError name="name" />
1110
+ </FormField>
1111
+ <FormSubmit>저장</FormSubmit>
1112
+ </FormRoot>;
1113
+ ```
1114
+
1115
+ _검증 + 비동기 제출:_
1116
+
1117
+ ```tsx
1118
+ import {
1119
+ useFormStore,
1120
+ FormRoot,
1121
+ FormField,
1122
+ FormControl,
1123
+ FormLabel,
1124
+ FormError,
1125
+ FormSubmit,
1126
+ Input,
1127
+ } from "@reopt-ai/opt-ui";
1128
+
1129
+ const store = useFormStore({
1130
+ defaultValues: { email: "" },
1131
+ validate: (values) => {
1132
+ const errors: Record<string, string> = {};
1133
+ if (!values.email) errors.email = "이메일을 입력하세요";
1134
+ return errors;
1135
+ },
1136
+ onSubmit: async (values) => {
1137
+ await fetch("/api/submit", {
1138
+ method: "POST",
1139
+ body: JSON.stringify(values),
1140
+ });
1141
+ },
1142
+ });
1143
+ ```
1144
+
1145
+ _schemaValidator (Zod):_
1146
+
1147
+ ```tsx
1148
+ import { useFormStore, schemaValidator } from "@reopt-ai/opt-ui";
1149
+ import { z } from "zod";
1150
+
1151
+ const schema = z.object({
1152
+ name: z.string().min(1, "필수 항목"),
1153
+ age: z.number().min(0, "0 이상"),
1154
+ });
1155
+
1156
+ const store = useFormStore({
1157
+ defaultValues: { name: "", age: 0 },
1158
+ validate: schemaValidator(schema),
1159
+ });
1160
+ ```
1161
+
1162
+ #### Button
1163
+
1164
+ **Import:** `import { Button } from "@reopt-ai/opt-ui"`
1165
+
1166
+ | Prop | Type | Required | Default | Description |
1167
+ | ----------- | ------------------------------------------------- | -------- | --------- | ----------------------------------------- |
1168
+ | `variant` | `"primary" \| "secondary" \| "ghost" \| "danger"` | | "primary" | 버튼 스타일 변형 |
1169
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 버튼 크기 |
1170
+ | `loading` | `boolean` | | false | 로딩 상태. true면 스피너 표시 및 비활성화 |
1171
+ | `leftIcon` | `ReactNode` | | | 버튼 텍스트 왼쪽에 표시할 아이콘 |
1172
+ | `rightIcon` | `ReactNode` | | | 버튼 텍스트 오른쪽에 표시할 아이콘 |
1173
+ | `disabled` | `boolean` | | | 비활성화 상태 |
1174
+
1175
+ **Examples:**
1176
+
1177
+ _버튼 변형:_
1178
+
1179
+ ```tsx
1180
+ import { Button } from "@reopt-ai/opt-ui";
1181
+
1182
+ <Button variant="primary">Primary</Button>
1183
+ <Button variant="secondary">Secondary</Button>
1184
+ <Button variant="ghost">Ghost</Button>
1185
+ <Button variant="danger" disabled>Danger</Button>
1186
+ <Button variant="primary" loading>저장 중...</Button>
1187
+ ```
1188
+
1189
+ #### Badge
1190
+
1191
+ **Import:** `import { Badge } from "@reopt-ai/opt-ui"`
1192
+
1193
+ | Prop | Type | Required | Default | Description |
1194
+ | -------------- | ---------------------------------------------------------- | -------- | --------- | -------------------------------------------- |
1195
+ | `variant` | `"default" \| "success" \| "warning" \| "error" \| "info"` | | "default" | 뱃지 색상 변형 |
1196
+ | `size` | `"sm" \| "md"` | | "md" | 뱃지 크기 |
1197
+ | `dot` | `boolean` | | false | 상태 점 표시 여부 |
1198
+ | `progress` | `number` | | | 원형 프로그레스 값 (0-100). 설정 시 dot 무시 |
1199
+ | `progressSize` | `number` | | 16 | 프로그레스 링 SVG 크기 (px) |
1200
+
1201
+ #### Spinner
1202
+
1203
+ **Import:** `import { Spinner } from "@reopt-ai/opt-ui"`
1204
+
1205
+ | Prop | Type | Required | Default | Description |
1206
+ | ------ | ---------------------- | -------- | ------- | ----------- |
1207
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 스피너 크기 |
1208
+
1209
+ #### Alert
1210
+
1211
+ **Import:** `import { Alert } from "@reopt-ai/opt-ui"`
1212
+
1213
+ | Prop | Type | Required | Default | Description |
1214
+ | ------------- | --------------------------------------------- | -------- | ------- | ----------------------------------------------------- |
1215
+ | `variant` | `"info" \| "success" \| "warning" \| "error"` | | "info" | 알림 변형 (색상 및 아이콘 결정) |
1216
+ | `title` | `string` | | | 알림 제목 |
1217
+ | `icon` | `ReactNode` | | | 커스텀 아이콘. 미지정 시 변형에 따른 기본 아이콘 사용 |
1218
+ | `dismissible` | `boolean` | | false | 닫기 버튼 표시 여부 |
1219
+ | `onDismiss` | `() => void` | | | 닫기 버튼 클릭 핸들러 |
1220
+
1221
+ #### Input
1222
+
1223
+ **Import:** `import { Input } from "@reopt-ai/opt-ui"`
1224
+
1225
+ | Prop | Type | Required | Default | Description |
1226
+ | ----------- | ----------- | -------- | ------- | ------------------------------------------- |
1227
+ | `label` | `string` | | | 입력 필드 레이블 |
1228
+ | `error` | `string` | | | 에러 메시지. 표시 시 aria-invalid=true 설정 |
1229
+ | `hint` | `string` | | | 힌트 텍스트 (에러 없을 때만 표시) |
1230
+ | `leftIcon` | `ReactNode` | | | 입력 필드 왼쪽에 표시할 아이콘 |
1231
+ | `rightIcon` | `ReactNode` | | | 입력 필드 오른쪽에 표시할 아이콘 |
1232
+ | `fullWidth` | `boolean` | | false | 전체 너비 사용 여부 |
1233
+
1234
+ **Examples:**
1235
+
1236
+ _기본 사용:_
1237
+
1238
+ ```tsx
1239
+ import { Input } from "@reopt-ai/opt-ui";
1240
+
1241
+ <Input
1242
+ label="이메일"
1243
+ hint="업무용 이메일을 입력하세요"
1244
+ placeholder="user@example.com"
1245
+ value={email}
1246
+ onChange={(e) => setEmail(e.target.value)}
1247
+ />;
1248
+ ```
1249
+
1250
+ _FormStore 연동:_
1251
+
1252
+ ```tsx
1253
+ import {
1254
+ useFormStore,
1255
+ FormRoot,
1256
+ FormField,
1257
+ FormControl,
1258
+ FormLabel,
1259
+ Input,
1260
+ } from "@reopt-ai/opt-ui";
1261
+
1262
+ const store = useFormStore({ defaultValues: { name: "" } });
1263
+
1264
+ <FormRoot store={store}>
1265
+ <FormField name="name">
1266
+ <FormLabel name="name">이름</FormLabel>
1267
+ <FormControl name="name">
1268
+ <Input />
1269
+ </FormControl>
1270
+ </FormField>
1271
+ </FormRoot>;
1272
+ ```
1273
+
1274
+ #### Switch
1275
+
1276
+ **Import:** `import { Switch } from "@reopt-ai/opt-ui"`
1277
+
1278
+ | Prop | Type | Required | Default | Description |
1279
+ | ---------------- | ---------------------------- | -------- | ------- | --------------------------- |
1280
+ | `label` | `string` | | | 스위치 레이블 |
1281
+ | `description` | `string` | | | 레이블 아래 설명 텍스트 |
1282
+ | `checked` | `boolean` | | | 제어 모드: 체크 상태 |
1283
+ | `defaultChecked` | `boolean` | | | 비제어 모드: 초기 체크 상태 |
1284
+ | `onChange` | `(checked: boolean) => void` | | | 상태 변경 핸들러 |
1285
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 스위치 크기 |
1286
+ | `disabled` | `boolean` | | | 비활성화 상태 |
1287
+
1288
+ #### Skeleton
1289
+
1290
+ **Import:** `import { Skeleton } from "@reopt-ai/opt-ui"`
1291
+
1292
+ **Skeleton:**
1293
+
1294
+ | Prop | Type | Required | Default | Description |
1295
+ | ---------- | --------------------------------------- | -------- | ------- | ----------------------- |
1296
+ | `variant` | `"text" \| "circular" \| "rectangular"` | | "text" | 스켈레톤 형태 |
1297
+ | `width` | `string \| number` | | | 너비 (px 또는 CSS 값) |
1298
+ | `height` | `string \| number` | | | 높이 (px 또는 CSS 값) |
1299
+ | `lines` | `number` | | 1 | text variant일 때 줄 수 |
1300
+ | `animated` | `boolean` | | true | 펄스 애니메이션 활성화 |
1301
+
1302
+ **SkeletonText:**
1303
+
1304
+ | Prop | Type | Required | Default | Description |
1305
+ | ------- | -------- | -------- | ------- | ------------ |
1306
+ | `lines` | `number` | | 3 | 텍스트 줄 수 |
1307
+
1308
+ **SkeletonAvatar:**
1309
+
1310
+ | Prop | Type | Required | Default | Description |
1311
+ | ------ | -------- | -------- | ------- | ---------------- |
1312
+ | `size` | `number` | | 40 | 아바타 크기 (px) |
1313
+
1314
+ **SkeletonTable:**
1315
+
1316
+ | Prop | Type | Required | Default | Description |
1317
+ | --------- | -------- | -------- | ------- | ------------ |
1318
+ | `rows` | `number` | | 5 | 테이블 행 수 |
1319
+ | `columns` | `number` | | 4 | 테이블 열 수 |
1320
+
1321
+ #### Textarea
1322
+
1323
+ **Import:** `import { Textarea } from "@reopt-ai/opt-ui"`
1324
+
1325
+ | Prop | Type | Required | Default | Description |
1326
+ | ----------- | ------------------------------------------------ | -------- | ---------- | ---------------- |
1327
+ | `label` | `string` | | | 입력 필드 레이블 |
1328
+ | `error` | `string` | | | 에러 메시지 |
1329
+ | `hint` | `string` | | | 힌트 텍스트 |
1330
+ | `fullWidth` | `boolean` | | false | 전체 너비 사용 |
1331
+ | `resize` | `"none" \| "vertical" \| "horizontal" \| "both"` | | "vertical" | 크기 조절 방향 |
1332
+ | `rows` | `number` | | 4 | 표시 줄 수 |
1333
+
1334
+ #### Avatar
1335
+
1336
+ **Import:** `import { Avatar } from "@reopt-ai/opt-ui"`
1337
+
1338
+ **Avatar:**
1339
+
1340
+ | Prop | Type | Required | Default | Description |
1341
+ | ---------- | ------------------------------------------- | -------- | ------- | -------------------------------------- |
1342
+ | `src` | `string` | | | 이미지 URL |
1343
+ | `alt` | `string` | | | 이미지 대체 텍스트 |
1344
+ | `name` | `string` | | | 사용자 이름 (이니셜 생성 및 색상 결정) |
1345
+ | `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | | "md" | 아바타 크기 |
1346
+ | `fallback` | `ReactNode` | | | 이미지 실패 시 표시할 콘텐츠 |
1347
+ | `status` | `"online" \| "offline" \| "busy" \| "away"` | | | 상태 인디케이터 |
1348
+
1349
+ **AvatarGroup:**
1350
+
1351
+ | Prop | Type | Required | Default | Description |
1352
+ | ---------- | -------------------------------------- | -------- | ------- | -------------- |
1353
+ | `max` | `number` | | 4 | 최대 표시 개수 |
1354
+ | `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | | "md" | 아바타 크기 |
1355
+ | `children` | `ReactNode` | Yes | | Avatar 요소들 |
1356
+
1357
+ #### Progress
1358
+
1359
+ **Import:** `import { Progress } from "@reopt-ai/opt-ui"`
1360
+
1361
+ **Progress:**
1362
+
1363
+ | Prop | Type | Required | Default | Description |
1364
+ | --------------- | ------------------------------------------------ | -------- | --------- | ------------------------------------ |
1365
+ | `value` | `number` | | | 현재 값. 생략하면 indeterminate 상태 |
1366
+ | `max` | `number` | | 100 | 최대 값 |
1367
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 진행바 높이 |
1368
+ | `variant` | `"default" \| "success" \| "warning" \| "error"` | | "default" | 색상 변형 |
1369
+ | `showLabel` | `boolean` | | false | 퍼센트 표시 |
1370
+ | `label` | `string` | | | 레이블 텍스트 |
1371
+ | `animated` | `boolean` | | true | 애니메이션 활성화 |
1372
+ | `indeterminate` | `boolean` | | false | 값을 알 수 없는 진행 상태 |
1373
+
1374
+ **CircularProgress:**
1375
+
1376
+ | Prop | Type | Required | Default | Description |
1377
+ | --------------- | ------------------------------------------------ | -------- | --------- | ------------------------------------ |
1378
+ | `value` | `number` | | | 현재 값. 생략하면 indeterminate 상태 |
1379
+ | `max` | `number` | | 100 | 최대 값 |
1380
+ | `size` | `number` | | 48 | 원 크기 (px) |
1381
+ | `strokeWidth` | `number` | | 4 | 선 두께 |
1382
+ | `variant` | `"default" \| "success" \| "warning" \| "error"` | | "default" | 색상 변형 |
1383
+ | `showLabel` | `boolean` | | false | 중앙에 퍼센트 표시 |
1384
+ | `label` | `string` | | | 접근성 레이블 |
1385
+ | `indeterminate` | `boolean` | | false | 값을 알 수 없는 진행 상태 |
1386
+
1387
+ #### Meter
1388
+
1389
+ **Import:** `import { Meter } from "@reopt-ai/opt-ui"`
1390
+
1391
+ | Prop | Type | Required | Default | Description |
1392
+ | ----------- | ------------------------------------------------ | -------- | --------- | ------------- |
1393
+ | `value` | `number` | Yes | | 현재 값 |
1394
+ | `min` | `number` | | 0 | 최소 값 |
1395
+ | `max` | `number` | | 100 | 최대 값 |
1396
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 게이지 높이 |
1397
+ | `variant` | `"default" \| "success" \| "warning" \| "error"` | | "default" | 색상 변형 |
1398
+ | `showValue` | `boolean` | | false | 퍼센트 표시 |
1399
+ | `label` | `string` | | | 레이블 텍스트 |
1400
+
1401
+ #### Breadcrumb
1402
+
1403
+ **Import:** `import { Breadcrumb } from "@reopt-ai/opt-ui"`
1404
+
1405
+ | Prop | Type | Required | Default | Description |
1406
+ | ------------ | -------------------------------- | -------- | ------- | ------------------------------------------- |
1407
+ | `items` | `BreadcrumbItem[]` | Yes | | 경로 항목 배열. { id, label, href?, icon? } |
1408
+ | `separator` | `ReactNode` | | "/" | 항목 간 구분자 |
1409
+ | `onNavigate` | `(item: BreadcrumbItem) => void` | | | 항목 클릭 핸들러 |
1410
+
1411
+ #### EmptyState
1412
+
1413
+ **Import:** `import { EmptyState } from "@reopt-ai/opt-ui"`
1414
+
1415
+ | Prop | Type | Required | Default | Description |
1416
+ | ------------- | -------------------- | -------- | ------- | -------------------------------------------- |
1417
+ | `title` | `string` | Yes | | 빈 상태 제목 |
1418
+ | `description` | `string` | | | 빈 상태 설명 |
1419
+ | `icon` | `ReactNode` | | | 표시할 아이콘 |
1420
+ | `actions` | `EmptyStateAction[]` | | | 액션 버튼 배열. { label, onClick, variant? } |
1421
+
1422
+ #### Card
1423
+
1424
+ **Import:** `import { Card } from "@reopt-ai/opt-ui"`
1425
+
1426
+ **Card:**
1427
+
1428
+ | Prop | Type | Required | Default | Description |
1429
+ | ------------------ | ----------------------------------- | -------- | --------- | ------------------------------ |
1430
+ | `variant` | `"default" \| "outline" \| "ghost"` | | "default" | 카드 스타일 변형 |
1431
+ | `padding` | `"none" \| "sm" \| "md" \| "lg"` | | "md" | 내부 패딩 크기 |
1432
+ | `selectable` | `boolean` | | false | 선택 가능 모드 활성화 |
1433
+ | `selected` | `boolean` | | | 선택 상태 (selectable=true 시) |
1434
+ | `onSelectedChange` | `(selected: boolean) => void` | | | 선택 상태 변경 콜백 |
1435
+
1436
+ **CardHeader:**
1437
+
1438
+ | Prop | Type | Required | Default | Description |
1439
+ | ---- | ---- | -------- | ------- | ----------- |
1440
+
1441
+ **CardTitle:**
1442
+
1443
+ | Prop | Type | Required | Default | Description |
1444
+ | ---- | ---- | -------- | ------- | ----------- |
1445
+
1446
+ **CardDescription:**
1447
+
1448
+ | Prop | Type | Required | Default | Description |
1449
+ | ---- | ---- | -------- | ------- | ----------- |
1450
+
1451
+ **CardContent:**
1452
+
1453
+ | Prop | Type | Required | Default | Description |
1454
+ | ---- | ---- | -------- | ------- | ----------- |
1455
+
1456
+ **CardFooter:**
1457
+
1458
+ | Prop | Type | Required | Default | Description |
1459
+ | ---- | ---- | -------- | ------- | ----------- |
1460
+
1461
+ **Examples:**
1462
+
1463
+ _카드 레이아웃:_
1464
+
1465
+ ```tsx
1466
+ import {
1467
+ Card,
1468
+ CardHeader,
1469
+ CardTitle,
1470
+ CardDescription,
1471
+ CardContent,
1472
+ } from "@reopt-ai/opt-ui";
1473
+
1474
+ <Card>
1475
+ <CardHeader>
1476
+ <CardTitle>프로젝트 요약</CardTitle>
1477
+ <CardDescription>최근 7일간 활동 현황</CardDescription>
1478
+ </CardHeader>
1479
+ <CardContent>
1480
+ <p>활성 사용자: 1,234명</p>
1481
+ </CardContent>
1482
+ </Card>;
1483
+ ```
1484
+
1485
+ #### Checkbox
1486
+
1487
+ **Import:** `import { Checkbox } from "@reopt-ai/opt-ui"`
1488
+
1489
+ **Checkbox:**
1490
+
1491
+ | Prop | Type | Required | Default | Description |
1492
+ | ---------------- | ---------------------------- | -------- | ------- | ---------------------------------- |
1493
+ | `label` | `string` | | | 체크박스 레이블 |
1494
+ | `description` | `string` | | | 레이블 아래 설명 텍스트 |
1495
+ | `checked` | `boolean` | | | 제어 모드: 체크 상태 |
1496
+ | `defaultChecked` | `boolean` | | | 비제어 모드: 초기 체크 상태 |
1497
+ | `onChange` | `(checked: boolean) => void` | | | 상태 변경 핸들러 |
1498
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 체크박스 크기 |
1499
+ | `value` | `string` | | | CheckboxGroup 내에서 사용할 값 |
1500
+ | `indeterminate` | `boolean` | | false | 불확정 상태 표시 (마이너스 아이콘) |
1501
+
1502
+ **CheckboxGroup:**
1503
+
1504
+ | Prop | Type | Required | Default | Description |
1505
+ | -------------- | ---------------------------- | -------- | ---------- | ------------------------------ |
1506
+ | `value` | `string[]` | | | 제어 모드: 선택된 값 배열 |
1507
+ | `defaultValue` | `string[]` | | [] | 비제어 모드: 초기 선택 값 배열 |
1508
+ | `onChange` | `(value: string[]) => void` | | | 선택 변경 핸들러 |
1509
+ | `orientation` | `"horizontal" \| "vertical"` | | "vertical" | 레이아웃 방향 |
1510
+ | `label` | `string` | | | 그룹 레이블 |
1511
+
1512
+ #### RadioGroup
1513
+
1514
+ **Import:** `import { RadioGroup } from "@reopt-ai/opt-ui"`
1515
+
1516
+ **RadioGroup:**
1517
+
1518
+ | Prop | Type | Required | Default | Description |
1519
+ | -------------- | ---------------------------- | -------- | ---------- | ------------------------- |
1520
+ | `value` | `string` | | | 제어 모드: 선택된 값 |
1521
+ | `defaultValue` | `string` | | "" | 비제어 모드: 초기 선택 값 |
1522
+ | `onChange` | `(value: string) => void` | | | 선택 변경 핸들러 |
1523
+ | `orientation` | `"horizontal" \| "vertical"` | | "vertical" | 레이아웃 방향 |
1524
+ | `label` | `string` | | | 그룹 레이블 |
1525
+ | `name` | `string` | | | 폼 제출 시 사용할 이름 |
1526
+
1527
+ **Radio:**
1528
+
1529
+ | Prop | Type | Required | Default | Description |
1530
+ | ------------- | ---------------------- | -------- | ------- | ---------------------------------------------------------- |
1531
+ | `value` | `string` | | | 라디오 값 (RadioGroup 안에서는 부모가 관리하므로 optional) |
1532
+ | `label` | `string` | | | 라디오 레이블 |
1533
+ | `description` | `string` | | | 레이블 아래 설명 텍스트 |
1534
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 라디오 크기 |
1535
+
1536
+ #### DateRangePicker
1537
+
1538
+ **Import:** `import { DateRangePicker } from "@reopt-ai/opt-ui"`
1539
+
1540
+ | Prop | Type | Required | Default | Description |
1541
+ | --------------------- | ----------------------------------------------------- | -------- | ------------------- | ------------------------------------------------------ |
1542
+ | `value` | `DateRange` | | | 제어 모드: { start: Date \| null, end: Date \| null } |
1543
+ | `onChange` | `(range: DateRange) => void` | | | 범위 변경 핸들러 |
1544
+ | `presets` | `DateRangePreset[]` | | | 빠른 선택 프리셋 배열 (기본: Today, Last 7/30/90 days) |
1545
+ | `placeholder` | `string` | | "Select date range" | 미선택 시 표시 텍스트 |
1546
+ | `label` | `string` | | | 입력 필드 레이블 |
1547
+ | `disabled` | `boolean` | | false | 비활성화 상태 |
1548
+ | `format` | `(date: Date) => string` | | | 날짜 포맷 함수 |
1549
+ | `comparison` | `boolean` | | false | 비교 모드 활성화 |
1550
+ | `comparisonMode` | `"previous" \| "year-over-year"` | | "previous" | 비교 기준 (이전 기간 / 전년 동기) |
1551
+ | `onComparisonChange` | `(comparison: boolean, mode: ComparisonMode) => void` | | | 비교 모드 변경 콜백 |
1552
+ | `showGranularity` | `boolean` | | false | 시간 단위 선택기 표시 |
1553
+ | `granularity` | `"hour" \| "day" \| "week" \| "month"` | | "day" | 시간 단위 |
1554
+ | `onGranularityChange` | `(granularity: DateGranularity) => void` | | | 시간 단위 변경 콜백 |
1555
+
1556
+ #### TagInput
1557
+
1558
+ **Import:** `import { TagInput } from "@reopt-ai/opt-ui"`
1559
+
1560
+ | Prop | Type | Required | Default | Description |
1561
+ | ----------------- | -------------------------- | -------- | ---------------- | ----------------------------------------- |
1562
+ | `value` | `string[]` | | | 제어 모드: 현재 태그 배열 |
1563
+ | `onChange` | `(tags: string[]) => void` | | | 태그 변경 핸들러 |
1564
+ | `placeholder` | `string` | | "Add tag..." | 입력 플레이스홀더 |
1565
+ | `label` | `string` | | | 입력 필드 레이블 |
1566
+ | `maxTags` | `number` | | | 최대 태그 수 |
1567
+ | `disabled` | `boolean` | | false | 비활성화 상태 |
1568
+ | `suggestions` | `string[]` | | | 자동완성 드롭다운에 표시할 추천 태그 목록 |
1569
+ | `delimiters` | `(string \| RegExp)[]` | | [",", ";", "\n"] | 붙여넣기 시 태그를 분할할 구분자 목록 |
1570
+ | `allowDuplicates` | `boolean` | | false | 중복 태그 허용 여부 |
1571
+
1572
+ #### ColorPicker
1573
+
1574
+ **Import:** `import { ColorPicker } from "@reopt-ai/opt-ui"`
1575
+
1576
+ | Prop | Type | Required | Default | Description |
1577
+ | ---------- | ------------------------- | -------- | ------- | -------------------------------------- |
1578
+ | `value` | `string` | | | 제어 모드: hex 색상 값 (예: '#3b82f6') |
1579
+ | `onChange` | `(color: string) => void` | | | 색상 변경 핸들러 |
1580
+ | `presets` | `string[]` | | | 프리셋 색상 배열 (기본 16색) |
1581
+ | `label` | `string` | | | 입력 필드 레이블 |
1582
+ | `disabled` | `boolean` | | false | 비활성화 상태 |
1583
+
1584
+ #### IconPicker
1585
+
1586
+ **Import:** `import { IconPicker } from "@reopt-ai/opt-ui"`
1587
+
1588
+ | Prop | Type | Required | Default | Description |
1589
+ | ---------- | -------------------------- | -------- | ------- | ------------------------------------------ |
1590
+ | `value` | `string` | | | 제어 모드: 선택된 아이콘 ID |
1591
+ | `onChange` | `(iconId: string) => void` | | | 아이콘 변경 핸들러 |
1592
+ | `icons` | `IconDef[]` | | | 아이콘 목록 (기본 24개 Lucide 아이콘 제공) |
1593
+ | `label` | `string` | | | 입력 필드 레이블 |
1594
+ | `disabled` | `boolean` | | false | 비활성화 상태 |
1595
+
1596
+ #### StepBuilder
1597
+
1598
+ **Import:** `import { StepBuilder } from "@reopt-ai/opt-ui"`
1599
+
1600
+ | Prop | Type | Required | Default | Description |
1601
+ | ---------- | ---------------------------- | -------- | ------- | --------------------------------------- |
1602
+ | `steps` | `StepDef[]` | Yes | | 단계 배열 ({ id, label, description? }) |
1603
+ | `onChange` | `(steps: StepDef[]) => void` | Yes | | 단계 변경 핸들러 |
1604
+ | `label` | `string` | | | 빌더 레이블 |
1605
+ | `maxSteps` | `number` | | | 최대 단계 수 |
1606
+
1607
+ #### ConditionBuilder
1608
+
1609
+ **Import:** `import { ConditionBuilder } from "@reopt-ai/opt-ui"`
1610
+
1611
+ | Prop | Type | Required | Default | Description |
1612
+ | --------------------- | --------------------------------------- | -------- | ------------------ | -------------------------------------- |
1613
+ | `groups` | `ConditionGroup[]` | Yes | | 조건 그룹 배열 |
1614
+ | `onChange` | `(groups: ConditionGroup[]) => void` | Yes | | 그룹 변경 핸들러 |
1615
+ | `properties` | `string[]` | | | 선택 가능한 속성 목록 (기본 10개 제공) |
1616
+ | `label` | `string` | | | 빌더 레이블 |
1617
+ | `nested` | `boolean` | | false | 중첩 AND/OR 그룹 활성화 |
1618
+ | `maxDepth` | `number` | | 3 | 최대 중첩 깊이 |
1619
+ | `conditionTypes` | `Record<string, ConditionTypeRenderer>` | | | 이질적 조건 타입 렌더러 레지스트리 |
1620
+ | `onPreview` | `(groups: ConditionGroup[]) => void` | | | 조건 변경 시 미리보기 콜백 |
1621
+ | `previewCount` | `number` | | | 매치 카운트 표시 (toLocaleString 포맷) |
1622
+ | `addNestedGroupLabel` | `string` | | "Add nested group" | 중첩 그룹 추가 버튼 텍스트 |
1623
+
1624
+ #### Popover
1625
+
1626
+ **Import:** `import { PopoverRoot } from "@reopt-ai/opt-ui"`
1627
+
1628
+ | Prop | Type | Required | Default | Description |
1629
+ | ----------- | -------- | -------- | ------- | -------------------- |
1630
+ | `gutter` | `number` | | 8 | 트리거와의 간격 (px) |
1631
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1632
+
1633
+ #### DropdownMenu
1634
+
1635
+ **Import:** `import { DropdownMenu } from "@reopt-ai/opt-ui"`
1636
+
1637
+ **DropdownContent:**
1638
+
1639
+ | Prop | Type | Required | Default | Description |
1640
+ | -------- | -------- | -------- | ------- | -------------------- |
1641
+ | `gutter` | `number` | | 4 | 트리거와의 간격 (px) |
1642
+
1643
+ **DropdownItem:**
1644
+
1645
+ | Prop | Type | Required | Default | Description |
1646
+ | ---------- | ---------------------------- | -------- | --------- | --------------------------------------------------- |
1647
+ | `variant` | `"default" \| "destructive"` | | "default" | 메뉴 아이템 시각 변형. destructive는 위험 작업 강조 |
1648
+ | `onClick` | `() => void` | | | 항목 클릭 핸들러 |
1649
+ | `disabled` | `boolean` | | | 비활성 상태 |
1650
+
1651
+ #### NumberInput
1652
+
1653
+ **Import:** `import { NumberInput } from "@reopt-ai/opt-ui"`
1654
+
1655
+ | Prop | Type | Required | Default | Description |
1656
+ | ---------------- | --------------------------------- | -------- | ------- | ------------------------------------------------ |
1657
+ | `value` | `number \| null` | | | 제어 모드 값. nullable=true일 때 null 허용 |
1658
+ | `defaultValue` | `number \| null` | | 0 | 비제어 모드 초기값. nullable=true일 때 null 허용 |
1659
+ | `onChange` | `(value: number \| null) => void` | | | 값 변경 핸들러 |
1660
+ | `nullable` | `boolean` | | false | 빈 값을 null로 커밋할지 여부 |
1661
+ | `clearable` | `boolean` | | false | nullable 값 지우기 버튼 표시 |
1662
+ | `min` | `number` | | | 최솟값 |
1663
+ | `max` | `number` | | | 최댓값 |
1664
+ | `step` | `number` | | 1 | 증감 단위 |
1665
+ | `label` | `string` | | | 라벨 텍스트 |
1666
+ | `unit` | `ReactNode` | | | 입력값 단위 suffix |
1667
+ | `disabled` | `boolean` | | | 비활성 상태 |
1668
+ | `disabledReason` | `string` | | | aria-disabled 상태에서 노출할 비활성 사유 |
1669
+ | `labels` | `NumberInputLabels` | | | 입력/증감/clear/invalid 접근성 문구 |
1670
+
1671
+ #### Slider
1672
+
1673
+ **Import:** `import { Slider } from "@reopt-ai/opt-ui"`
1674
+
1675
+ | Prop | Type | Required | Default | Description |
1676
+ | -------------- | --------------------------- | -------- | ------- | ------------------ |
1677
+ | `value` | `number` | | | 제어 모드 값 |
1678
+ | `defaultValue` | `number` | | 0 | 비제어 모드 초기값 |
1679
+ | `onChange` | `(value: number) => void` | | | 값 변경 핸들러 |
1680
+ | `min` | `number` | | 0 | 최솟값 |
1681
+ | `max` | `number` | | 100 | 최댓값 |
1682
+ | `step` | `number` | | 1 | 증감 단위 |
1683
+ | `label` | `string` | | | 레이블 텍스트 |
1684
+ | `showValue` | `boolean` | | false | 현재 값 표시 여부 |
1685
+ | `formatValue` | `(value: number) => string` | | | 값 포맷 함수 |
1686
+ | `disabled` | `boolean` | | | 비활성화 |
1687
+ | `className` | `string` | | | 최외곽 CSS 클래스 |
1688
+
1689
+ #### PageHeader
1690
+
1691
+ **Import:** `import { PageHeader } from "@reopt-ai/opt-ui"`
1692
+
1693
+ | Prop | Type | Required | Default | Description |
1694
+ | ------------- | ----------- | -------- | ------- | ----------------------------------- |
1695
+ | `title` | `string` | Yes | | 페이지 제목 |
1696
+ | `description` | `string` | | | 제목 아래 설명 텍스트 |
1697
+ | `actions` | `ReactNode` | | | 오른쪽에 표시할 액션 슬롯 (버튼 등) |
1698
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1699
+
1700
+ #### ScrollArea
1701
+
1702
+ **Import:** `import { ScrollArea } from "@reopt-ai/opt-ui"`
1703
+
1704
+ | Prop | Type | Required | Default | Description |
1705
+ | ------------- | -------------------------------------- | -------- | ---------- | ----------------- |
1706
+ | `children` | `ReactNode` | Yes | | 스크롤할 콘텐츠 |
1707
+ | `orientation` | `"vertical" \| "horizontal" \| "both"` | | "vertical" | 스크롤 방향 |
1708
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1709
+
1710
+ #### Container
1711
+
1712
+ **Import:** `import { Container } from "@reopt-ai/opt-ui"`
1713
+
1714
+ | Prop | Type | Required | Default | Description |
1715
+ | ----------- | ------------------------------------------------- | -------- | ------- | ------------------------ |
1716
+ | `children` | `ReactNode` | Yes | | 래핑할 콘텐츠 |
1717
+ | `maxWidth` | `"sm" \| "md" \| "lg" \| "xl" \| "2xl" \| "full"` | | "xl" | 최대 너비 크기 |
1718
+ | `center` | `boolean` | | true | 중앙 정렬 여부 (mx-auto) |
1719
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1720
+
1721
+ #### Section
1722
+
1723
+ **Import:** `import { Section } from "@reopt-ai/opt-ui"`
1724
+
1725
+ | Prop | Type | Required | Default | Description |
1726
+ | ------------- | ----------- | -------- | ------- | --------------------- |
1727
+ | `children` | `ReactNode` | Yes | | 섹션 콘텐츠 |
1728
+ | `title` | `string` | | | 섹션 제목 (h3) |
1729
+ | `description` | `string` | | | 제목 아래 설명 텍스트 |
1730
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1731
+
1732
+ #### Resizable
1733
+
1734
+ **Import:** `import { ResizablePanelGroup } from "@reopt-ai/opt-ui"`
1735
+
1736
+ **ResizablePanelGroup:**
1737
+
1738
+ | Prop | Type | Required | Default | Description |
1739
+ | ------------ | ---------------------------- | -------- | ------- | ---------------------------------------- |
1740
+ | `direction` | `"horizontal" \| "vertical"` | Yes | | 패널 분할 방향 |
1741
+ | `children` | `ReactNode` | Yes | | ResizablePanel + ResizableHandle 조합 |
1742
+ | `autoSaveId` | `string` | | | 로컬 스토리지에 크기 상태 저장 (고유 ID) |
1743
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1744
+
1745
+ **ResizablePanel:**
1746
+
1747
+ | Prop | Type | Required | Default | Description |
1748
+ | ------------- | ----------- | -------- | ------- | ----------------------------- |
1749
+ | `defaultSize` | `number` | | | 초기 크기 (퍼센트, 0-100) |
1750
+ | `minSize` | `number` | | | 최소 크기 (퍼센트) |
1751
+ | `maxSize` | `number` | | | 최대 크기 (퍼센트) |
1752
+ | `collapsible` | `boolean` | | false | 최소 크기 이하 시 접히기 허용 |
1753
+ | `children` | `ReactNode` | Yes | | 패널 콘텐츠 |
1754
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1755
+
1756
+ **ResizableHandle:**
1757
+
1758
+ | Prop | Type | Required | Default | Description |
1759
+ | ------------ | --------- | -------- | ------- | ----------------------- |
1760
+ | `withHandle` | `boolean` | | false | 시각적 드래그 핸들 표시 |
1761
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1762
+
1763
+ #### BlockLayout
1764
+
1765
+ **Import:** `import { BlockLayout } from "@reopt-ai/opt-ui"`
1766
+
1767
+ | Prop | Type | Required | Default | Description |
1768
+ | -------------- | --------------------------------------------- | -------- | --------- | ------------------------------------------------------------------------------------ |
1769
+ | `children` | `ReactNode` | Yes | | Block 콘텐츠 |
1770
+ | `loading` | `boolean` | | | 로딩 상태. 설정 시 LoadingOverlay로 자동 래핑 |
1771
+ | `loadingLabel` | `string` | | | LoadingOverlay 접근성 레이블 |
1772
+ | `spacing` | `"section" \| "group" \| "element" \| "none"` | | "section" | Block 최상위 자식 사이 간격. 데이터 밀도가 높은 Block는 group/element로 낮출 수 있음 |
1773
+ | `className` | `string` | | | 기본 스타일 오버라이드 |
1774
+
1775
+ **Examples:**
1776
+
1777
+ _Block 루트:_
1778
+
1779
+ ```tsx
1780
+ import { BlockLayout, PageHeader } from "@reopt-ai/opt-ui";
1781
+
1782
+ <BlockLayout loading={isLoading} spacing="section">
1783
+ <PageHeader title="대시보드" description="프로젝트 현황" />
1784
+ <section>콘텐츠 영역</section>
1785
+ </BlockLayout>;
1786
+ ```
1787
+
1788
+ #### createBlock
1789
+
1790
+ **Import:** `import { createBlock } from "@reopt-ai/opt-ui"`
1791
+
1792
+ | Prop | Type | Required | Default | Description |
1793
+ | ------------------------- | --------------------------------------------------------- | -------- | ------- | ----------------------------------- |
1794
+ | `name` | `string` | Yes | | 컴포넌트 displayName |
1795
+ | `render` | `(props: Omit<P, 'loading' \| 'className'>) => ReactNode` | Yes | | 콘텐츠를 반환하는 렌더 함수 |
1796
+ | `options.layoutClassName` | `string` | | | BlockLayout에 전달할 기본 className |
1797
+
1798
+ **Examples:**
1799
+
1800
+ _Block 팩토리:_
1801
+
1802
+ ```tsx
1803
+ import { createBlock, PageHeader } from "@reopt-ai/opt-ui";
1804
+
1805
+ interface MyDashboardProps {
1806
+ title: string;
1807
+ count: number;
1808
+ }
1809
+
1810
+ const MyDashboard = createBlock<MyDashboardProps>(
1811
+ "MyDashboard",
1812
+ ({ title, count }) => (
1813
+ <>
1814
+ <PageHeader title={title} />
1815
+ <p>항목 수: {count}</p>
1816
+ </>
1817
+ ),
1818
+ );
1819
+
1820
+ // loading, className은 자동 처리
1821
+ <MyDashboard title="개요" count={42} loading={false} />;
1822
+ ```
1823
+
1824
+ #### Logo
1825
+
1826
+ **Import:** `import { Logo } from "@reopt-ai/opt-ui"`
1827
+
1828
+ | Prop | Type | Required | Default | Description |
1829
+ | ----------- | ---------------------- | -------- | ------- | -------------------------------- |
1830
+ | `src` | `string` | | | 로고 이미지 URL |
1831
+ | `icon` | `ReactNode` | | | 로고 아이콘 — src 미설정 시 표시 |
1832
+ | `text` | `string` | | | 텍스트 레이블 |
1833
+ | `alt` | `string` | | "Logo" | 이미지 alt 텍스트 |
1834
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 크기 (sm=24px, md=32px, lg=40px) |
1835
+ | `href` | `string` | | | 링크 URL — 설정 시 <a>로 래핑 |
1836
+ | `onClick` | `() => void` | | | 클릭 핸들러 |
1837
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1838
+
1839
+ #### Drawer
1840
+
1841
+ **Import:** `import { DrawerRoot } from "@reopt-ai/opt-ui"`
1842
+
1843
+ **DrawerRoot:**
1844
+
1845
+ | Prop | Type | Required | Default | Description |
1846
+ | --------- | ------------ | -------- | ------- | ------------------- |
1847
+ | `open` | `boolean` | | | 제어 모드 열림 상태 |
1848
+ | `onClose` | `() => void` | | | 닫힘 콜백 |
1849
+
1850
+ **DrawerPanel:**
1851
+
1852
+ | Prop | Type | Required | Default | Description |
1853
+ | ----------------------- | -------------------------------- | -------- | ------- | -------------------------------------- |
1854
+ | `side` | `"left" \| "right" \| "bottom"` | | "right" | 슬라이드 방향 |
1855
+ | `size` | `"sm" \| "md" \| "lg" \| "full"` | | "md" | 패널 크기 |
1856
+ | `swipeToDismiss` | `boolean` | | true | 가장자리 방향으로 드래그해 닫기 활성화 |
1857
+ | `swipeDismissThreshold` | `number` | | 80 | 닫힘 커밋에 필요한 드래그 거리(px) |
1858
+
1859
+ #### Pagination
1860
+
1861
+ **Import:** `import { Pagination } from "@reopt-ai/opt-ui"`
1862
+
1863
+ | Prop | Type | Required | Default | Description |
1864
+ | ----------------- | ------------------------------------------- | -------- | ------------ | ------------------------------------------- |
1865
+ | `totalItems` | `number` | | | 전체 항목 수 |
1866
+ | `totalPages` | `number` | | | 전체 페이지 수. 전체 항목 수를 모를 때 사용 |
1867
+ | `hasMore` | `boolean` | | | cursor pagination에서 다음 페이지 존재 여부 |
1868
+ | `pageSize` | `number` | | | 페이지당 항목 수 |
1869
+ | `currentPage` | `number` | Yes | | 현재 페이지 (1부터 시작) |
1870
+ | `onPageChange` | `(page: number) => void` | Yes | | 페이지 변경 콜백 |
1871
+ | `showPageNumbers` | `boolean` | | true | 페이지 번호 표시 여부 |
1872
+ | `siblingCount` | `number` | | 1 | 현재 페이지 좌우 표시할 페이지 수 |
1873
+ | `variant` | `"pages" \| "count" \| "compact" \| "none"` | | "pages" | 중앙 표시 방식 |
1874
+ | `isDisabled` | `boolean` | | false | 전체 pagination 비활성화 |
1875
+ | `label` | `string` | | "Pagination" | navigation landmark 접근성 라벨 |
1876
+ | `labels` | `PaginationLabels` | | | Prev/Next/page/count 접근성 및 표시 문구 |
1877
+
1878
+ #### VirtualList
1879
+
1880
+ **Import:** `import { VirtualList } from "@reopt-ai/opt-ui"`
1881
+
1882
+ | Prop | Type | Required | Default | Description |
1883
+ | ------------ | --------------------------------------- | -------- | ------- | --------------------------------- |
1884
+ | `items` | `T[]` | Yes | | 렌더링할 항목 배열 |
1885
+ | `renderItem` | `(item: T, index: number) => ReactNode` | Yes | | 항목 렌더 함수 |
1886
+ | `itemHeight` | `number` | Yes | | 각 항목의 고정 높이(px) |
1887
+ | `overscan` | `number` | | 3 | 뷰포트 밖에 미리 렌더링할 항목 수 |
1888
+
1889
+ #### LoadingOverlay
1890
+
1891
+ **Import:** `import { LoadingOverlay } from "@reopt-ai/opt-ui"`
1892
+ **Dependencies:** spinner (core)
1893
+
1894
+ | Prop | Type | Required | Default | Description |
1895
+ | ---------- | ----------- | -------- | ---------- | ------------- |
1896
+ | `loading` | `boolean` | Yes | | 로딩 상태 |
1897
+ | `children` | `ReactNode` | Yes | | 감싸는 콘텐츠 |
1898
+ | `label` | `string` | | "Loading…" | 로딩 텍스트 |
1899
+
1900
+ #### StarRating
1901
+
1902
+ **Import:** `import { StarRating } from "@reopt-ai/opt-ui"`
1903
+
1904
+ | Prop | Type | Required | Default | Description |
1905
+ | ---------- | ------------------------- | -------- | ------- | ---------------- |
1906
+ | `value` | `number` | | | 현재 선택된 별점 |
1907
+ | `onChange` | `(value: number) => void` | | | 별점 변경 콜백 |
1908
+ | `max` | `number` | | 5 | 최대 별 개수 |
1909
+ | `readOnly` | `boolean` | | false | 읽기 전용 모드 |
1910
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 별 아이콘 크기 |
1911
+
1912
+ #### ErrorBoundary
1913
+
1914
+ **Import:** `import { ErrorBoundary } from "@reopt-ai/opt-ui"`
1915
+
1916
+ | Prop | Type | Required | Default | Description |
1917
+ | ---------- | -------------------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------- |
1918
+ | `children` | `ReactNode` | Yes | | 에러를 감시할 자식 컴포넌트 |
1919
+ | `fallback` | `ReactNode \| ((error: Error) => ReactNode)` | | | 에러 발생 시 표시할 UI. 함수 전달 시 에러 객체를 인자로 받음. 미지정 시 Alert error 표시 |
1920
+ | `onError` | `(error: Error, info: ErrorInfo) => void` | | | 에러 발생 시 호출되는 콜백 (에러 리포팅용) |
1921
+
1922
+ #### Command
1923
+
1924
+ **Import:** `import { Command } from "@reopt-ai/opt-ui"`
1925
+
1926
+ **Command:**
1927
+
1928
+ | Prop | Type | Required | Default | Description |
1929
+ | -------------- | ---------------------------------------------------------------- | -------- | ------- | --------------------------------------------------- |
1930
+ | `shouldFilter` | `boolean` | | | 자동 필터링 여부 (기본 true) |
1931
+ | `filter` | `(value: string, search: string, keywords: string[]) => boolean` | | | 커스텀 필터 함수 (기본: case-insensitive substring) |
1932
+
1933
+ **CommandInput:**
1934
+
1935
+ | Prop | Type | Required | Default | Description |
1936
+ | ------------------ | ----------- | -------- | ------- | ----------------------------------- |
1937
+ | `trailing` | `ReactNode` | | | 검색 입력 우측에 표시할 보조 콘텐츠 |
1938
+ | `wrapperClassName` | `string` | | | 입력 wrapper className |
1939
+
1940
+ **CommandList:**
1941
+
1942
+ | Prop | Type | Required | Default | Description |
1943
+ | ------------ | -------- | -------- | ---------- | ------------------- |
1944
+ | `aria-label` | `string` | | "Commands" | listbox 접근성 라벨 |
1945
+
1946
+ **CommandItem:**
1947
+
1948
+ | Prop | Type | Required | Default | Description |
1949
+ | ---------- | ------------------------- | -------- | ------- | ---------------------------------------- |
1950
+ | `value` | `string` | Yes | | 이 항목의 검색 가능 값 (고유 식별자) |
1951
+ | `keywords` | `string[]` | | | value에 더해 검색어와 비교할 추가 키워드 |
1952
+ | `onSelect` | `(value: string) => void` | | | Enter/클릭 시 호출 |
1953
+
1954
+ #### ShaderSurface
1955
+
1956
+ **Import:** `import { ShaderSurface } from "@reopt-ai/opt-ui"`
1957
+
1958
+ | Prop | Type | Required | Default | Description |
1959
+ | ------------ | ---------------- | -------- | ------- | ------------------------------------------ |
1960
+ | `preset` | `ShaderPresetId` | Yes | | 렌더할 셰이더 프리셋 id |
1961
+ | `colors` | `string[]` | | | hex 색상 배열 (미지정 시 프리셋 기본 색) |
1962
+ | `scale` | `number` | | | 패턴 스케일 |
1963
+ | `speed` | `number` | | | 애니메이션 속도 |
1964
+ | `distortion` | `number` | | | 왜곡 강도 |
1965
+ | `grain` | `number` | | | 필름 그레인 양 |
1966
+ | `contrast` | `number` | | | 하이라이트 대비 |
1967
+ | `angle` | `number` | | | 회전 각도(도) |
1968
+ | `paused` | `boolean` | | | true면 단일 프레임만 렌더 (카드 배경 등) |
1969
+ | `dpr` | `number` | | | device pixel ratio 상한 (기본 min(dpr, 2)) |
1970
+
1971
+ ### Visual Layer
1972
+
1973
+ ### Shell Layer
1974
+
1975
+ #### FaqAccordion
1976
+
1977
+ **Import:** `import { FaqAccordion } from "@reopt-ai/opt-ui"`
1978
+ **Dependencies:** disclosure (core)
1979
+
1980
+ | Prop | Type | Required | Default | Description |
1981
+ | ------- | ----------- | -------- | ------- | --------------------------------------- |
1982
+ | `items` | `FaqItem[]` | Yes | | FAQ 항목 배열. { id, question, answer } |
1983
+
1984
+ #### PageAside
1985
+
1986
+ **Import:** `import { PageAside } from "@reopt-ai/opt-ui"`
1987
+
1988
+ | Prop | Type | Required | Default | Description |
1989
+ | ---------------- | ----------- | -------- | ------- | -------------------------------------- |
1990
+ | `header` | `ReactNode` | | | 상단 고정 슬롯 (예: package switcher). |
1991
+ | `children` | `ReactNode` | Yes | | 스크롤 가능한 네비게이션 영역. |
1992
+ | `footer` | `ReactNode` | | | 하단 고정 슬롯 (예: version label). |
1993
+ | `widthClassName` | `string` | | | 너비 Tailwind 클래스. 기본값 `w-60`. |
1994
+ | `label` | `string` | | | `<aside>`의 aria-label. |
1995
+ | `hideOnMobile` | `boolean` | | | md 아래에서 숨김. 기본값 true. |
1996
+
1997
+ #### ContentTabs
1998
+
1999
+ **Import:** `import { ContentTabs } from "@reopt-ai/opt-ui"`
2000
+ **Dependencies:** tabs (core)
2001
+
2002
+ | Prop | Type | Required | Default | Description |
2003
+ | -------------- | ---------- | -------- | ------- | ------------------------------------ |
2004
+ | `tabs` | `TabDef[]` | Yes | | 탭 정의 배열. { id, label, content } |
2005
+ | `defaultTabId` | `string` | | | 초기 선택 탭 ID. 미지정 시 첫 탭 |
2006
+
2007
+ #### DashboardGrid
2008
+
2009
+ **Import:** `import { DashboardGrid } from "@reopt-ai/opt-ui"`
2010
+ **Dependencies:** stat-card (core), composite-zone (core)
2011
+
2012
+ | Prop | Type | Required | Default | Description |
2013
+ | --------- | ------------ | -------- | ------- | ----------------------------------------------------- |
2014
+ | `stats` | `StatCard[]` | Yes | | 통계 데이터 배열. { id, title, value, change, trend } |
2015
+ | `columns` | `number` | | 3 | 행당 컬럼 수 |
2016
+
2017
+ #### SearchCombobox
2018
+
2019
+ **Import:** `import { SearchCombobox } from "@reopt-ai/opt-ui"`
2020
+ **Dependencies:** combobox (core)
2021
+
2022
+ | Prop | Type | Required | Default | Description |
2023
+ | ------------- | -------------------------------------- | -------- | --------- | -------------------------------- |
2024
+ | `items` | `string[]` | Yes | | 검색 대상 문자열 목록 |
2025
+ | `placeholder` | `string` | | "검색..." | 입력 플레이스홀더 |
2026
+ | `label` | `string` | | "검색" | 입력 레이블 |
2027
+ | `onSelect` | `(item: string) => void` | | | 항목 선택 핸들러 |
2028
+ | `labels` | `SearchComboboxLabels` | | | noResults/loading 문구 |
2029
+ | `async` | `boolean` | | false | 비동기 검색 모드 활성화 |
2030
+ | `onSearch` | `(query: string) => Promise<string[]>` | | | async=true일 때 사용할 검색 콜백 |
2031
+ | `debounceMs` | `number` | | 300 | 비동기 검색 디바운스 ms |
2032
+
2033
+ **Examples:**
2034
+
2035
+ _검색 + 선택:_
2036
+
2037
+ ```tsx
2038
+ import { SearchCombobox } from "@reopt-ai/opt-ui";
2039
+
2040
+ <SearchCombobox
2041
+ items={["React", "Vue", "Angular", "Svelte"]}
2042
+ placeholder="프레임워크 검색..."
2043
+ onSelect={(item) => console.log(item)}
2044
+ />;
2045
+ ```
2046
+
2047
+ #### StatusSelect
2048
+
2049
+ **Import:** `import { StatusSelect } from "@reopt-ai/opt-ui"`
2050
+ **Dependencies:** select (core)
2051
+
2052
+ | Prop | Type | Required | Default | Description |
2053
+ | ---------- | ------------------------- | -------- | ------- | ----------------------------------- |
2054
+ | `options` | `SelectOption[]` | Yes | | 옵션 목록. { value, label, color? } |
2055
+ | `value` | `string` | | | 제어 모드: 현재 선택 값 |
2056
+ | `onChange` | `(value: string) => void` | | | 제어 모드: 값 변경 핸들러 |
2057
+ | `label` | `string` | | "상태" | Select 레이블 |
2058
+
2059
+ #### EditorToolbar
2060
+
2061
+ **Import:** `import { EditorToolbar } from "@reopt-ai/opt-ui"`
2062
+ **Dependencies:** toolbar (core)
2063
+
2064
+ | Prop | Type | Required | Default | Description |
2065
+ | --------------- | ---------------------- | -------- | ------- | ------------------------------------------ |
2066
+ | `buttons` | `ToolbarButtonDef[]` | Yes | | 버튼 정의. { id, label, icon, separator? } |
2067
+ | `onAction` | `(id: string) => void` | | | 버튼 클릭 핸들러 |
2068
+ | `activeButtons` | `string[]` | | [] | 활성 상태 버튼 ID 배열 |
2069
+
2070
+ #### SidebarNav
2071
+
2072
+ **Import:** `import { SidebarNav } from "@reopt-ai/opt-ui"`
2073
+
2074
+ | Prop | Type | Required | Default | Description |
2075
+ | ------- | -------------- | -------- | ------- | --------------------------------------------------------------- |
2076
+ | `items` | `NavItemDef[]` | Yes | | 네비게이션 항목. { id, label, href, separator?, sectionLabel? } |
2077
+
2078
+ #### SettingsForm
2079
+
2080
+ **Import:** `import { SettingsForm } from "@reopt-ai/opt-ui"`
2081
+ **Dependencies:** form (core), checkbox (core), radio-group (core), switch (core)
2082
+
2083
+ | Prop | Type | Required | Default | Description |
2084
+ | ---------- | ------------------------------------------- | -------- | ------- | ----------------- |
2085
+ | `fields` | `FormFieldDef[]` | Yes | | 폼 필드 정의 배열 |
2086
+ | `onSubmit` | `(values: Record<string, unknown>) => void` | | | 제출 핸들러 |
2087
+
2088
+ **Examples:**
2089
+
2090
+ _설정 폼:_
2091
+
2092
+ ```tsx
2093
+ import { SettingsForm } from "@reopt-ai/opt-ui";
2094
+
2095
+ const fields = [
2096
+ { name: "username", label: "사용자명", type: "text", required: true },
2097
+ { name: "theme", label: "테마", type: "select", options: ["light", "dark"] },
2098
+ { name: "notifications", label: "알림", type: "switch" },
2099
+ ];
2100
+
2101
+ <SettingsForm fields={fields} onSubmit={(values) => console.log(values)} />;
2102
+ ```
2103
+
2104
+ #### AppMenubar
2105
+
2106
+ **Import:** `import { AppMenubar } from "@reopt-ai/opt-ui"`
2107
+ **Dependencies:** menu (core), kbd (core)
2108
+
2109
+ | Prop | Type | Required | Default | Description |
2110
+ | ------- | ----------- | -------- | ------- | --------------------------------------------------- |
2111
+ | `menus` | `MenuDef[]` | Yes | | 메뉴 정의 배열. { id, label, items: MenuItemDef[] } |
2112
+
2113
+ #### CommandPalette
2114
+
2115
+ **Import:** `import { CommandPalette } from "@reopt-ai/opt-ui"`
2116
+ **Dependencies:** dialog (core), combobox (core), kbd (core)
2117
+
2118
+ | Prop | Type | Required | Default | Description |
2119
+ | --------------- | -------------------------------------------- | -------- | ------- | ----------------------------------------------------- |
2120
+ | `commands` | `Omit<Command, "action">[]` | Yes | | 커맨드 목록. { id, label, group, shortcut? } |
2121
+ | `open` | `boolean` | Yes | | 열림 상태 |
2122
+ | `onOpenChange` | `(open: boolean) => void` | Yes | | 상태 변경 핸들러 |
2123
+ | `onSelect` | `(command: Omit<Command, 'action'>) => void` | | | 커맨드 선택 핸들러 |
2124
+ | `inline` | `boolean` | | false | true일 때 풀스크린 Dialog 대신 인라인 팝업으로 렌더링 |
2125
+ | `labels` | `CommandPaletteLabels` | | | title/description/input/list/empty/escape 문구 |
2126
+ | `footer` | `ReactNode` | | | 명령 목록 아래에 표시할 footer slot |
2127
+ | `empty` | `ReactNode` | | | 결과가 없을 때 표시할 empty slot |
2128
+ | `inputTrailing` | `ReactNode` | | | 검색 입력 우측 보조 콘텐츠 |
2129
+
2130
+ #### CommandPaletteTrigger
2131
+
2132
+ **Import:** `import { CommandPaletteTrigger } from "@reopt-ai/opt-ui"`
2133
+ **Dependencies:** command-palette (shells)
2134
+
2135
+ | Prop | Type | Required | Default | Description |
2136
+ | ---------- | -------------------------------------------- | -------- | ------- | -------------------------------------------------- |
2137
+ | `commands` | `Omit<Command, "action">[]` | Yes | | 커맨드 목록 |
2138
+ | `onSelect` | `(command: Omit<Command, 'action'>) => void` | | | 커맨드 선택 핸들러 |
2139
+ | `labels` | `CommandPaletteTriggerLabels` | | | 내부 CommandPalette에 전달할 title/input/list 문구 |
2140
+
2141
+ #### DeploymentTimeline
2142
+
2143
+ **Import:** `import { DeploymentTimeline } from "@reopt-ai/opt-ui"`
2144
+
2145
+ | Prop | Type | Required | Default | Description |
2146
+ | ------- | ------------------ | -------- | --------------- | -------------------------------------------------------- |
2147
+ | `steps` | `DeploymentStep[]` | Yes | | 배포 단계 배열. { id, name, status, duration?, detail? } |
2148
+ | `title` | `string` | | "배포 타임라인" | 타임라인 제목 |
2149
+
2150
+ #### ProjectSwitcher
2151
+
2152
+ **Import:** `import { ProjectSwitcher } from "@reopt-ai/opt-ui"`
2153
+ **Dependencies:** combobox (core)
2154
+
2155
+ | Prop | Type | Required | Default | Description |
2156
+ | ------------- | ---------------------- | -------- | ------------------ | ------------------------------------------------------- |
2157
+ | `projects` | `ProjectDef[]` | Yes | | 프로젝트 목록. { id, name, framework, status, domain? } |
2158
+ | `value` | `string` | | | 제어 모드: 현재 선택된 프로젝트 ID |
2159
+ | `onChange` | `(id: string) => void` | | | 프로젝트 선택 핸들러 |
2160
+ | `placeholder` | `string` | | "프로젝트 검색..." | 검색 입력 플레이스홀더 |
2161
+
2162
+ #### EnvPanel
2163
+
2164
+ **Import:** `import { EnvPanel } from "@reopt-ai/opt-ui"`
2165
+ **Dependencies:** disclosure (core)
2166
+
2167
+ | Prop | Type | Required | Default | Description |
2168
+ | -------- | --------------- | -------- | ------- | ------------------------------------------ |
2169
+ | `groups` | `EnvGroupDef[]` | Yes | | 환경 그룹 배열. { env, vars: EnvVarDef[] } |
2170
+
2171
+ #### BranchSelect
2172
+
2173
+ **Import:** `import { BranchSelect } from "@reopt-ai/opt-ui"`
2174
+ **Dependencies:** select (core)
2175
+
2176
+ | Prop | Type | Required | Default | Description |
2177
+ | ---------- | ------------------------ | -------- | -------- | ------------------------------------------------------- |
2178
+ | `branches` | `BranchDef[]` | Yes | | 브랜치 목록. { name, isDefault?, lastCommit?, author? } |
2179
+ | `value` | `string` | | | 제어 모드: 현재 선택된 브랜치 이름 |
2180
+ | `onChange` | `(name: string) => void` | | | 브랜치 선택 핸들러 |
2181
+ | `label` | `string` | | "브랜치" | Select 레이블 |
2182
+
2183
+ #### DomainTable
2184
+
2185
+ **Import:** `import { DomainTable } from "@reopt-ai/opt-ui"`
2186
+
2187
+ | Prop | Type | Required | Default | Description |
2188
+ | --------- | ------------- | -------- | -------- | --------------------------------------------------------- |
2189
+ | `domains` | `DomainDef[]` | Yes | | 도메인 목록. { domain, status, ssl, redirect?, addedAt? } |
2190
+ | `title` | `string` | | "도메인" | 테이블 제목 |
2191
+
2192
+ #### DataTable
2193
+
2194
+ **Import:** `import { DataTable } from "@reopt-ai/opt-ui"`
2195
+ **Dependencies:** composite-zone (core), button (core), checkbox (core)
2196
+
2197
+ **DataTable:**
2198
+
2199
+ | Prop | Type | Required | Default | Description |
2200
+ | -------------- | -------------------- | -------- | ------------------- | --------------------------------------------------- |
2201
+ | `data` | `T[]` | Yes | | 테이블 데이터 배열 |
2202
+ | `columns` | `ColumnDef<T>[]` | Yes | | 컬럼 정의. { id, header, accessor, width?, align? } |
2203
+ | `keyExtractor` | `(row: T) => string` | Yes | | 각 행의 고유 키 추출 함수 |
2204
+ | `title` | `string` | | "데이터 테이블" | 테이블 제목 |
2205
+ | `onRowClick` | `(row: T) => void` | | | 행 클릭 핸들러 |
2206
+ | `emptyMessage` | `string` | | "데이터가 없습니다" | 데이터 없을 때 표시할 메시지 |
2207
+
2208
+ **ColumnDef:**
2209
+
2210
+ | Prop | Type | Required | Default | Description |
2211
+ | ---------- | -------------------- | -------- | ----------- | ------------------------------------------------------------ |
2212
+ | `bar` | `(row: T) => number` | | | 인라인 프로그레스 바 비율(0-1) 계산 함수. 범위 밖/NaN은 보정 |
2213
+ | `barColor` | `string` | | "bg-accent" | 인라인 바 색상 클래스 |
2214
+
2215
+ **Examples:**
2216
+
2217
+ _기본 테이블:_
2218
+
2219
+ ```tsx
2220
+ import { DataTable } from "@reopt-ai/opt-ui";
2221
+
2222
+ const columns = [
2223
+ { id: "name", header: "이름", accessor: (r) => r.name },
2224
+ { id: "email", header: "이메일", accessor: (r) => r.email },
2225
+ ];
2226
+ const data = [
2227
+ { name: "홍길동", email: "hong@example.com" },
2228
+ { name: "김철수", email: "kim@example.com" },
2229
+ ];
2230
+
2231
+ <DataTable columns={columns} data={data} keyExtractor={(r) => r.email} />;
2232
+ ```
2233
+
2234
+ _선택 + 정렬:_
2235
+
2236
+ ```tsx
2237
+ import { DataTable } from "@reopt-ai/opt-ui";
2238
+
2239
+ <DataTable
2240
+ columns={columns}
2241
+ data={data}
2242
+ keyExtractor={(r) => r.id}
2243
+ selectable
2244
+ selectedKeys={selected}
2245
+ onSelectionChange={setSelected}
2246
+ sortable
2247
+ onSort={(colId, dir) => console.log(colId, dir)}
2248
+ />;
2249
+ ```
2250
+
2251
+ #### NotificationToast
2252
+
2253
+ **Import:** `import { ToastProvider } from "@reopt-ai/opt-ui"`
2254
+ **Dependencies:** alert (core)
2255
+
2256
+ **ToastProvider:**
2257
+
2258
+ | Prop | Type | Required | Default | Description |
2259
+ | ----------------- | -------------------------------------------------------------- | -------- | ----------- | ------------------- |
2260
+ | `children` | `ReactNode` | Yes | | 앱 컨텐츠 |
2261
+ | `position` | `"top-right" \| "top-left" \| "bottom-right" \| "bottom-left"` | | "top-right" | 토스트 표시 위치 |
2262
+ | `defaultDuration` | `number` | | 5000 | 기본 표시 시간 (ms) |
2263
+
2264
+ **useToast:**
2265
+
2266
+ | Prop | Type | Required | Default | Description |
2267
+ | --------- | ----------------------------------- | -------- | ------- | ------------------------ |
2268
+ | `returns` | `{ toasts, addToast, removeToast }` | | | 토스트 상태 및 제어 함수 |
2269
+
2270
+ **toast:**
2271
+
2272
+ | Prop | Type | Required | Default | Description |
2273
+ | ---------------------------------------- | --------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------ |
2274
+ | `toast.success / error / info / warning` | `(message: string, options?) => string` | | | 훅 없이 어디서든 호출하는 프로그램매틱 API. toast.dismiss(id) / toast.clear()도 제공 |
2275
+
2276
+ **NotificationToast:**
2277
+
2278
+ | Prop | Type | Required | Default | Description |
2279
+ | ----------- | -------------- | -------- | ------- | ------------------ |
2280
+ | `toast` | `ToastMessage` | Yes | | 토스트 메시지 객체 |
2281
+ | `onDismiss` | `() => void` | Yes | | 닫기 핸들러 |
2282
+
2283
+ #### DesignGuidePanel
2284
+
2285
+ **Import:** `import { DesignGuidePanel } from "@reopt-ai/opt-ui"`
2286
+
2287
+ | Prop | Type | Required | Default | Description |
2288
+ | ----------- | -------- | -------- | ------- | --------------- |
2289
+ | `className` | `string` | | | 추가 CSS 클래스 |
2290
+
2291
+ #### TaskList
2292
+
2293
+ **Import:** `import { TaskList } from "@reopt-ai/opt-ui"`
2294
+ **Dependencies:** avatar (core), checkbox (core)
2295
+
2296
+ | Prop | Type | Required | Default | Description |
2297
+ | -------------------- | --------------------------------------------- | -------- | ----------- | ---------------------------------------------------------- |
2298
+ | `tasks` | `TaskDef[]` | Yes | | 작업 배열. { id, title, status, priority, assignee?, ... } |
2299
+ | `title` | `string` | | "작업 목록" | 섹션 제목 |
2300
+ | `onTaskClick` | `(task: TaskDef) => void` | | | 작업 클릭 핸들러 |
2301
+ | `onTaskStatusChange` | `(task: TaskDef, completed: boolean) => void` | | | 완료 상태 변경 핸들러 |
2302
+ | `showSubtasks` | `boolean` | | false | 하위 작업 표시 여부 |
2303
+
2304
+ #### ActivityFeed
2305
+
2306
+ **Import:** `import { ActivityFeed } from "@reopt-ai/opt-ui"`
2307
+ **Dependencies:** avatar (core)
2308
+
2309
+ | Prop | Type | Required | Default | Description |
2310
+ | ----------------- | -------------------------------------- | -------- | ----------- | ----------------------------------------------------- |
2311
+ | `activities` | `ActivityDef[]` | Yes | | 활동 배열. { id, type, title, actor, timestamp, ... } |
2312
+ | `title` | `string` | | "활동 피드" | 섹션 제목 |
2313
+ | `maxItems` | `number` | | | 최대 표시 개수 |
2314
+ | `onActivityClick` | `(activity: ActivityDef) => void` | | | 활동 클릭 핸들러 |
2315
+ | `layout` | `"list" \| "compact"` | | "list" | 시간 표시 레이아웃 모드 |
2316
+ | `renderActions` | `(activity: ActivityDef) => ReactNode` | | | 각 활동 항목 우측 액션 슬롯 렌더 함수 |
2317
+
2318
+ #### FilterBar
2319
+
2320
+ **Import:** `import { FilterBar } from "@reopt-ai/opt-ui"`
2321
+ **Dependencies:** select (core), input (core), button (core), switch (core), checkbox (core), date-range-picker (core)
2322
+
2323
+ | Prop | Type | Required | Default | Description |
2324
+ | ---------------- | ------------------------------------------------------- | -------- | ------- | ----------------------------------------------------- |
2325
+ | `filters` | `FilterGroupDef[]` | Yes | | 필터 그룹 배열. { id, label, type, options?, value? } |
2326
+ | `onFilterChange` | `(filterId: string, value: string \| string[]) => void` | | | 필터 변경 핸들러 |
2327
+ | `onClearAll` | `() => void` | | | 모든 필터 초기화 핸들러 |
2328
+
2329
+ **Examples:**
2330
+
2331
+ _필터 바:_
2332
+
2333
+ ```tsx
2334
+ import { FilterBar } from "@reopt-ai/opt-ui";
2335
+
2336
+ const filters = [
2337
+ { id: "status", label: "상태", type: "select", options: ["활성", "비활성"] },
2338
+ { id: "search", label: "검색", type: "search" },
2339
+ ];
2340
+
2341
+ <FilterBar
2342
+ filters={filters}
2343
+ onFilterChange={(id, value) => console.log(id, value)}
2344
+ onClearAll={() => console.log("clear")}
2345
+ />;
2346
+ ```
2347
+
2348
+ #### QuickActions
2349
+
2350
+ **Import:** `import { QuickActions } from "@reopt-ai/opt-ui"`
2351
+ **Dependencies:** kbd (core)
2352
+
2353
+ | Prop | Type | Required | Default | Description |
2354
+ | --------- | ------------------ | -------- | ----------- | ----------------------------------------------------------------- |
2355
+ | `actions` | `QuickActionDef[]` | Yes | | 작업 배열. { id, label, description?, icon?, shortcut?, onClick } |
2356
+ | `title` | `string` | | "빠른 작업" | 섹션 제목 |
2357
+ | `layout` | `"grid" \| "list"` | | "grid" | 레이아웃 모드 |
2358
+ | `columns` | `2 \| 3 \| 4` | | 3 | 그리드 컬럼 수 |
2359
+
2360
+ #### TeamMemberList
2361
+
2362
+ **Import:** `import { TeamMemberList } from "@reopt-ai/opt-ui"`
2363
+ **Dependencies:** avatar (core)
2364
+
2365
+ | Prop | Type | Required | Default | Description |
2366
+ | --------------- | --------------------------------------- | -------- | ------- | ------------------------------------------------------- |
2367
+ | `members` | `TeamMemberDef[]` | Yes | | 팀원 배열. { id, name, email, avatar?, role?, status? } |
2368
+ | `title` | `string` | | "팀원" | 섹션 제목 |
2369
+ | `layout` | `"list" \| "compact" \| "avatars-only"` | | "list" | 레이아웃 모드 |
2370
+ | `maxDisplay` | `number` | | | 최대 표시 인원 |
2371
+ | `onMemberClick` | `(member: TeamMemberDef) => void` | | | 팀원 클릭 핸들러 |
2372
+
2373
+ #### AuthForm
2374
+
2375
+ **Import:** `import { AuthForm } from "@reopt-ai/opt-ui"`
2376
+ **Dependencies:** form (core)
2377
+
2378
+ | Prop | Type | Required | Default | Description |
2379
+ | ------------------- | ---------------------------------------------------------------------------- | -------- | ------- | -------------------------------------------- |
2380
+ | `defaultMode` | `"login" \| "signup"` | | "login" | 초기 모드 (비제어) |
2381
+ | `mode` | `"login" \| "signup"` | | | 제어 모드: 현재 모드 |
2382
+ | `onModeChange` | `(mode: "login" \| "signup") => void` | | | 모드 변경 핸들러 |
2383
+ | `showRememberMe` | `boolean` | | true | 로그인 모드에서 '로그인 상태 유지' 표시 여부 |
2384
+ | `minPasswordLength` | `number` | | 8 | 비밀번호 최소 길이 |
2385
+ | `onSubmit` | `(values: { email, password, confirmPassword?, rememberMe?, mode }) => void` | | | 제출 핸들러 |
2386
+ | `labels` | `AuthFormLabels` | | | i18n용 라벨 오버라이드 |
2387
+
2388
+ #### WizardForm
2389
+
2390
+ **Import:** `import { WizardForm } from "@reopt-ai/opt-ui"`
2391
+ **Dependencies:** form (core), checkbox (core), radio-group (core)
2392
+
2393
+ | Prop | Type | Required | Default | Description |
2394
+ | -------------- | ------------------------------------------- | -------- | ------- | ------------------------------------------ |
2395
+ | `fields` | `FormFieldDef[]` | Yes | | 폼 필드 정의 배열 |
2396
+ | `steps` | `WizardStepDef[]` | Yes | | 단계 정의. { id, label, fields: string[] } |
2397
+ | `showReview` | `boolean` | | true | 마지막 리뷰 단계 표시 여부 |
2398
+ | `onSubmit` | `(values: Record<string, unknown>) => void` | | | 제출 핸들러 |
2399
+ | `onStepChange` | `(stepIndex: number) => void` | | | 단계 변경 핸들러 |
2400
+ | `labels` | `WizardFormLabels` | | | i18n용 라벨 오버라이드 |
2401
+
2402
+ #### DynamicFieldForm
2403
+
2404
+ **Import:** `import { DynamicFieldForm } from "@reopt-ai/opt-ui"`
2405
+ **Dependencies:** form (core)
2406
+
2407
+ | Prop | Type | Required | Default | Description |
2408
+ | --------------- | ------------------------------------------------------- | -------- | ------- | ---------------------- |
2409
+ | `initialCount` | `number` | | 1 | 초기 필드 수 |
2410
+ | `minFields` | `number` | | 1 | 최소 필드 수 |
2411
+ | `maxFields` | `number` | | | 최대 필드 수 |
2412
+ | `fieldType` | `"text" \| "email" \| "url" \| "number"` | | "text" | 필드 입력 타입 |
2413
+ | `validateField` | `(value: string, index: number) => string \| undefined` | | | 커스텀 필드 검증 함수 |
2414
+ | `onSubmit` | `(values: string[]) => void` | | | 제출 핸들러 |
2415
+ | `labels` | `DynamicFieldFormLabels` | | | i18n용 라벨 오버라이드 |
2416
+
2417
+ #### FileUploadForm
2418
+
2419
+ **Import:** `import { FileUploadForm } from "@reopt-ai/opt-ui"`
2420
+ **Dependencies:** form (core)
2421
+
2422
+ | Prop | Type | Required | Default | Description |
2423
+ | ----------------- | ------------------------------------------------ | -------- | -------------------------- | ----------------------------------------- |
2424
+ | `accept` | `string` | | "image/\*,.pdf,.doc,.docx" | 허용 파일 타입 |
2425
+ | `showPreview` | `boolean` | | true | 이미지 미리보기 표시 |
2426
+ | `showFileInfo` | `boolean` | | true | 파일 정보 표시 |
2427
+ | `showDescription` | `boolean` | | true | 설명 텍스트영역 표시 |
2428
+ | `maxFileSize` | `number` | | | 최대 파일 크기 (bytes) |
2429
+ | `onSubmit` | `(values: { title, description, file }) => void` | | | 제출 핸들러 |
2430
+ | `labels` | `FileUploadFormLabels` | | | i18n용 라벨 오버라이드 |
2431
+ | `onPreview` | `(file: File) => void` | | | 파일 선택 후 프리뷰 콜백 |
2432
+ | `columnMapping` | `ReactNode` | | | CSV 컬럼 매핑 UI 슬롯 (파일 선택 후 표시) |
2433
+
2434
+ #### EventIcon
2435
+
2436
+ **Import:** `import { EventIcon } from "@reopt-ai/opt-ui"`
2437
+
2438
+ | Prop | Type | Required | Default | Description |
2439
+ | ------- | --------------------------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------- |
2440
+ | `icon` | `string \| React.ReactNode` | Yes | | semantic icon key, legacy key, 또는 React 노드 (Lucide 등) |
2441
+ | `color` | `string` | | theme accent | 사용자 지정 아이콘 색상. 없으면 theme accent 토큰을 사용하고, 전달하면 전경색과 tint 배경에 적용됩니다. |
2442
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 아이콘 크기 (sm=20px, md=28px, lg=36px) |
2443
+
2444
+ #### TemplatePicker
2445
+
2446
+ **Import:** `import { TemplatePicker } from "@reopt-ai/opt-ui"`
2447
+
2448
+ | Prop | Type | Required | Default | Description |
2449
+ | ------------ | ------------------------------ | -------- | ------- | --------------------------------------------------------------------------- |
2450
+ | `templates` | `TemplateDef[]` | Yes | | 템플릿 배열. { id, name, description?, icon?, category?, featured?, tags? } |
2451
+ | `selected` | `string` | | | 현재 선택된 템플릿 ID |
2452
+ | `onSelect` | `(templateId: string) => void` | Yes | | 템플릿 선택 핸들러 |
2453
+ | `showSearch` | `boolean` | | false | 검색 입력 표시 여부 |
2454
+
2455
+ #### FailureList
2456
+
2457
+ **Import:** `import { FailureList } from "@reopt-ai/opt-ui"`
2458
+ **Dependencies:** badge (core)
2459
+
2460
+ | Prop | Type | Required | Default | Description |
2461
+ | ---------------- | ------------------------------------- | -------- | ----------- | -------------------------------------------------------------------- |
2462
+ | `failures` | `FailureItem[]` | Yes | | 실패 항목 배열. { id, title, message?, severity, timestamp, group? } |
2463
+ | `title` | `string` | | "최근 실패" | 섹션 제목 |
2464
+ | `maxItems` | `number` | | | 최대 표시 개수 |
2465
+ | `grouped` | `boolean` | | false | group 필드 기준으로 그룹핑 표시 |
2466
+ | `onFailureClick` | `(failure: FailureItem) => void` | | | 실패 항목 클릭 핸들러 |
2467
+ | `renderActions` | `(failure: FailureItem) => ReactNode` | | | 각 항목 우측 액션 슬롯 렌더 함수 |
2468
+
2469
+ #### KeyValueEditor
2470
+
2471
+ **Import:** `import { KeyValueEditor } from "@reopt-ai/opt-ui"`
2472
+
2473
+ | Prop | Type | Required | Default | Description |
2474
+ | ------------------ | ---------------------------------------------------------------- | -------- | ------- | --------------------------------- |
2475
+ | `value` | `KeyValueEntry[]` | | | 현재 엔트리 (controlled 모드) |
2476
+ | `defaultValue` | `KeyValueEntry[]` | | | 초기 엔트리 (uncontrolled 모드) |
2477
+ | `onChange` | `(entries: KeyValueEntry[]) => void` | | | 엔트리 변경 핸들러 |
2478
+ | `showSecretToggle` | `boolean` | | false | 비밀값 표시/숨김 토글 버튼 활성화 |
2479
+ | `maxEntries` | `number` | | | 최대 항목 수 제한 |
2480
+ | `readOnly` | `boolean` | | false | 읽기 전용 모드 |
2481
+ | `labels` | `KeyValueEditorLabels` | | | i18n 라벨 오버라이드 |
2482
+ | `renderActions` | `(entry: KeyValueEntry, index: number) => ReactNode` | | | 항목별 커스텀 액션 슬롯 |
2483
+ | `validateKey` | `(key: string, entries: KeyValueEntry[]) => string \| undefined` | | | 키 유효성 검사 함수 |
2484
+
2485
+ #### WorkflowCanvas
2486
+
2487
+ **Import:** `import { WorkflowCanvas } from "@reopt-ai/opt-ui"`
2488
+ **Dependencies:** badge (core)
2489
+
2490
+ | Prop | Type | Required | Default | Description |
2491
+ | -------------- | ---------------------------------------------------- | -------- | ------- | ------------------------------------------- |
2492
+ | `steps` | `WorkflowCanvasStep[]` | Yes | | 스텝 배열. { id, title, row, col, status? } |
2493
+ | `connections` | `WorkflowCanvasConnection[]` | | [] | 연결선 배열. { from, to, label? } |
2494
+ | `onStepMove` | `(stepId: string, row: number, col: number) => void` | | | 화살표 키 이동 핸들러 |
2495
+ | `onSelectStep` | `(step: WorkflowCanvasStep) => void` | | | 스텝 선택 핸들러 |
2496
+
2497
+ #### CodeSnippetViewer
2498
+
2499
+ **Import:** `import { CodeSnippetViewer } from "@reopt-ai/opt-ui"`
2500
+
2501
+ | Prop | Type | Required | Default | Description |
2502
+ | ----------------- | ---------------------------------------------- | -------- | --------- | --------------------------------- |
2503
+ | `code` | `string` | Yes | | 표시할 코드 문자열 |
2504
+ | `language` | `string` | | "text" | 코드 언어 라벨 |
2505
+ | `title` | `string` | | | 헤더에 표시할 제목 |
2506
+ | `showLineNumbers` | `boolean` | | true | 줄 번호 표시 여부 |
2507
+ | `showCopyButton` | `boolean` | | true | 복사 버튼 표시 여부 |
2508
+ | `maxHeight` | `number` | | 400 | 스크롤 영역의 최대 높이(px) |
2509
+ | `syntaxTheme` | `"default" \| "muted" \| "dark" \| "terminal"` | | "default" | 코드 블록 색상 톤 |
2510
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2511
+ | `labels` | `CodeSnippetViewerLabels` | | | 복사 버튼과 코드 영역 레이블 문구 |
2512
+
2513
+ #### QueryResultsTable
2514
+
2515
+ **Import:** `import { QueryResultsTable } from "@reopt-ai/opt-ui"`
2516
+
2517
+ | Prop | Type | Required | Default | Description |
2518
+ | --------- | -------------------------------- | -------- | ------- | ----------------------- |
2519
+ | `columns` | `string[]` | Yes | | 컬럼 이름 |
2520
+ | `rows` | `Array<Record<string, unknown>>` | Yes | | 결과 행 |
2521
+ | `loading` | `boolean` | | | polite 로딩 상태 |
2522
+ | `error` | `string` | | | assertive 오류 상태 |
2523
+ | `labels` | `QueryResultsTableLabels` | | | 로딩/빈 상태/행 수 문구 |
2524
+
2525
+ #### ReportBuilder
2526
+
2527
+ **Import:** `import { ReportBuilder } from "@reopt-ai/opt-ui"`
2528
+ **Dependencies:** button (core), input (core)
2529
+
2530
+ | Prop | Type | Required | Default | Description |
2531
+ | ------------- | ------------------------------------------------------------------ | -------- | ------- | ----------------------------------- |
2532
+ | `chartTypes` | `ChartTypeDef[]` | | | 차트 타입 그리드 (기본 9종 제공) |
2533
+ | `dataSources` | `DataSourceDef[]` | | | 데이터 소스 드롭다운 옵션 |
2534
+ | `configForm` | `ReactNode` | | | 차트별 데이터 설정 폼 슬롯 (step 2) |
2535
+ | `styleForm` | `ReactNode` | | | 차트별 스타일 설정 폼 슬롯 (step 3) |
2536
+ | `preview` | `ReactNode` | | | 차트 미리보기 슬롯 (step 4) |
2537
+ | `onSave` | `(report: { name, description, chartType, dataSourceId }) => void` | | | 저장 콜백 |
2538
+ | `onCancel` | `() => void` | | | 취소 콜백 |
2539
+ | `labels` | `ReportBuilderLabels` | | | UI 텍스트 커스터마이징 |
2540
+
2541
+ #### InsightsPanel
2542
+
2543
+ **Import:** `import { InsightsPanel } from "@reopt-ai/opt-ui"`
2544
+ **Dependencies:** button (core), stat-card (core), badge (core)
2545
+
2546
+ | Prop | Type | Required | Default | Description |
2547
+ | ------------------------- | ----------------------------------- | -------- | ------- | -------------------------------------------------- |
2548
+ | `insights` | `InsightItem[]` | Yes | | 인사이트 항목 배열 |
2549
+ | `stats` | `InsightsStat[]` | | | 통계 필터 카드 배열 (클릭 가능) |
2550
+ | `detectionTypes` | `DetectionTypeDef[]` | | | 검출 유형 토글 배열 (volume_anomaly, new_event 등) |
2551
+ | `detectionConfig` | `DetectionConfig` | | | 검출 파라미터 (days, zScoreThreshold) |
2552
+ | `onDetectionConfigChange` | `(config: DetectionConfig) => void` | | | 검출 파라미터 변경 핸들러 |
2553
+ | `onDismiss` | `(id: string) => void` | | | 인사이트 dismiss 핸들러 |
2554
+
2555
+ #### TimeRangeSelector
2556
+
2557
+ **Import:** `import { TimeRangeSelector } from "@reopt-ai/opt-ui"`
2558
+ **Dependencies:** button (core), popover (core), date-range-picker (core)
2559
+
2560
+ | Prop | Type | Required | Default | Description |
2561
+ | ---------- | ---------------------------- | -------- | ------- | ------------------------------------ |
2562
+ | `value` | `DateRange` | | | 현재 선택된 날짜 범위 |
2563
+ | `onChange` | `(range: DateRange) => void` | | | 범위 변경 핸들러 |
2564
+ | `presets` | `TimePresetDef[]` | | | 빠른 프리셋 목록 (Today, Last 7d 등) |
2565
+ | `labels` | `TimeRangeSelectorLabels` | | | i18n용 라벨 오버라이드 |
2566
+
2567
+ #### ExportButton
2568
+
2569
+ **Import:** `import { ExportButton } from "@reopt-ai/opt-ui"`
2570
+ **Dependencies:** dropdown-menu (core), button (core)
2571
+
2572
+ | Prop | Type | Required | Default | Description |
2573
+ | ---------- | -------------------------------- | -------- | --------------- | ------------------------ |
2574
+ | `data` | `Record<string, unknown>[]` | Yes | | 내보낼 데이터 배열 |
2575
+ | `columns` | `ExportColumn[]` | | | 컬럼 매핑 (key → header) |
2576
+ | `fileName` | `string` | | "export" | 파일 이름 |
2577
+ | `formats` | `ExportFormat[]` | | ["csv", "json"] | 지원 포맷 |
2578
+ | `onExport` | `(format: ExportFormat) => void` | | | 커스텀 내보내기 핸들러 |
2579
+
2580
+ #### SummaryRow
2581
+
2582
+ **Import:** `import { SummaryRow } from "@reopt-ai/opt-ui"`
2583
+ **Dependencies:** stat-card (core), skeleton (core)
2584
+
2585
+ | Prop | Type | Required | Default | Description |
2586
+ | -------------------------- | -------------------------------- | -------- | ------- | -------------------------------- |
2587
+ | `stats` | `StatCardType[]` | Yes | | 통계 카드 배열 |
2588
+ | `columns` | `2 \| 3 \| 4` | | 4 | 컬럼 수 |
2589
+ | `onStatClick` | `(stat: StatCardType) => void` | | | 카드 클릭 핸들러 |
2590
+ | `formatValue` | `(stat: StatCardType) => string` | | | 값 표시 커스텀 포맷 함수 |
2591
+ | `durationFractionDigits` | `number` | | 1 | duration 포맷 시 소수점 자리수 |
2592
+ | `percentageFractionDigits` | `number` | | 1 | percentage 포맷 시 소수점 자리수 |
2593
+ | `loading` | `boolean` | | false | 로딩 시 스켈레톤 표시 |
2594
+
2595
+ #### ComparisonSelector
2596
+
2597
+ **Import:** `import { ComparisonSelector } from "@reopt-ai/opt-ui"`
2598
+ **Dependencies:** select (core), button (core)
2599
+
2600
+ | Prop | Type | Required | Default | Description |
2601
+ | ----------- | -------------------------- | -------- | ------- | ------------------------- |
2602
+ | `segments` | `ComparisonOption[]` | Yes | | 선택 가능한 세그먼트 목록 |
2603
+ | `valueA` | `string` | | | Base 선택값 |
2604
+ | `valueB` | `string` | | | Compare 선택값 |
2605
+ | `onChangeA` | `(value: string) => void` | | | Base 변경 핸들러 |
2606
+ | `onChangeB` | `(value: string) => void` | | | Compare 변경 핸들러 |
2607
+ | `labels` | `ComparisonSelectorLabels` | | | i18n용 라벨 오버라이드 |
2608
+
2609
+ #### ThemeSwitcher
2610
+
2611
+ **Import:** `import { ThemeSwitcher } from "@reopt-ai/opt-ui"`
2612
+
2613
+ | Prop | Type | Required | Default | Description |
2614
+ | -------- | --------------------- | -------- | ------- | ---------------------- |
2615
+ | `labels` | `ThemeSwitcherLabels` | | | i18n용 라벨 오버라이드 |
2616
+
2617
+ #### PromptTemplate
2618
+
2619
+ **Import:** `import { PromptTemplate } from "@reopt-ai/opt-ui"`
2620
+ **Dependencies:** input (core)
2621
+
2622
+ | Prop | Type | Required | Default | Description |
2623
+ | ------------- | ---------------------- | -------- | ------- | ------------------------------------------------------------ |
2624
+ | `title` | `string` | Yes | | 프롬프트 제목 |
2625
+ | `description` | `string` | | | 프롬프트 설명 (헤더 아래 표시) |
2626
+ | `template` | `string` | Yes | | 프롬프트 템플릿. {변수명}으로 치환 가능 |
2627
+ | `variables` | `PromptVariable[]` | | | 변수 정의 배열. { name, label, placeholder?, defaultValue? } |
2628
+ | `labels` | `PromptTemplateLabels` | | | i18n용 라벨 오버라이드 |
2629
+
2630
+ #### Sidebar
2631
+
2632
+ **Import:** `import { Sidebar } from "@reopt-ai/opt-ui"`
2633
+ **Dependencies:** sidebar-nav (shells)
2634
+
2635
+ **Sidebar:**
2636
+
2637
+ | Prop | Type | Required | Default | Description |
2638
+ | ------------------- | ------------------------------ | -------- | ---------- | --------------------------------------------------------- |
2639
+ | `children` | `ReactNode` | Yes | | Sidebar.Header, Sidebar.Content, Sidebar.Footer 자식 요소 |
2640
+ | `collapsible` | `boolean` | | false | 접기/펼치기 토글 지원 |
2641
+ | `defaultCollapsed` | `boolean` | | false | 초기 접힘 상태 |
2642
+ | `collapsed` | `boolean` | | | 제어 모드: 접힘 상태 |
2643
+ | `onCollapsedChange` | `(collapsed: boolean) => void` | | | 제어 모드: 접힘 상태 변경 핸들러 |
2644
+ | `width` | `number` | | 280 | 펼침 상태 너비 (px) |
2645
+ | `collapsedWidth` | `number` | | 56 | 접힘 상태 너비 (px) |
2646
+ | `side` | `"left" \| "right"` | | "left" | 사이드바 위치 |
2647
+ | `label` | `string` | | "사이드바" | aside aria-label |
2648
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2649
+
2650
+ **Sidebar.Group:**
2651
+
2652
+ | Prop | Type | Required | Default | Description |
2653
+ | ----------- | ----------- | -------- | ------- | ---------------------------------- |
2654
+ | `children` | `ReactNode` | Yes | | Sidebar.Item 요소들 |
2655
+ | `label` | `string` | | | 그룹 레이블 (접힌 상태에서 숨겨짐) |
2656
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2657
+
2658
+ **Sidebar.Item:**
2659
+
2660
+ | Prop | Type | Required | Default | Description |
2661
+ | ----------- | ------------ | -------- | ------- | ------------------------------------------------------------- |
2662
+ | `children` | `ReactNode` | Yes | | 항목 레이블 텍스트 |
2663
+ | `icon` | `ReactNode` | | | 아이콘 (접힌 상태에서도 표시) |
2664
+ | `active` | `boolean` | | false | 활성 상태 (aria-current=page) |
2665
+ | `onClick` | `() => void` | | | 클릭 핸들러 |
2666
+ | `href` | `string` | | | 링크 URL — 설정 시 <a> 태그로 렌더링 |
2667
+ | `tooltip` | `string` | | | 접힌 상태에서 Tooltip 표시 (미지정 시 children 텍스트) |
2668
+ | `badge` | `ReactNode` | | | 우측 배지 (숫자/텍스트). 접힌 상태에서 아이콘 위 dot으로 축소 |
2669
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2670
+
2671
+ #### AppShell
2672
+
2673
+ **Import:** `import { AppShell } from "@reopt-ai/opt-ui"`
2674
+ **Dependencies:** sidebar (shells), page-header (core)
2675
+
2676
+ | Prop | Type | Required | Default | Description |
2677
+ | ----------- | ----------- | -------- | ------- | ------------------------------------------------------------------------------ |
2678
+ | `children` | `ReactNode` | Yes | | AppShell.Header, AppShell.Sidebar, AppShell.Content, AppShell.Footer 자식 요소 |
2679
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2680
+
2681
+ **Examples:**
2682
+
2683
+ _앱 레이아웃:_
2684
+
2685
+ ```tsx
2686
+ import { AppShell } from "@reopt-ai/opt-ui";
2687
+
2688
+ <AppShell>
2689
+ <AppShell.Header>헤더 영역</AppShell.Header>
2690
+ <AppShell.Sidebar>사이드바 영역</AppShell.Sidebar>
2691
+ <AppShell.Content>메인 콘텐츠</AppShell.Content>
2692
+ </AppShell>;
2693
+ ```
2694
+
2695
+ #### ConfirmDialog
2696
+
2697
+ **Import:** `import { ConfirmDialog } from "@reopt-ai/opt-ui"`
2698
+ **Dependencies:** dialog (core)
2699
+
2700
+ | Prop | Type | Required | Default | Description |
2701
+ | -------------- | ----------------------- | -------- | --------- | ---------------- |
2702
+ | `open` | `boolean` | Yes | | 열림 상태 |
2703
+ | `onConfirm` | `() => void` | Yes | | 확인 콜백 |
2704
+ | `onCancel` | `() => void` | Yes | | 취소 콜백 |
2705
+ | `title` | `string` | Yes | | 대화 상자 제목 |
2706
+ | `description` | `string` | | | 설명 텍스트 |
2707
+ | `confirmLabel` | `string` | | "Confirm" | 확인 버튼 텍스트 |
2708
+ | `cancelLabel` | `string` | | "Cancel" | 취소 버튼 텍스트 |
2709
+ | `variant` | `"default" \| "danger"` | | "default" | 변형 |
2710
+
2711
+ #### AsyncCombobox
2712
+
2713
+ **Import:** `import { AsyncCombobox } from "@reopt-ai/opt-ui"`
2714
+ **Dependencies:** combobox (core), spinner (core)
2715
+
2716
+ | Prop | Type | Required | Default | Description |
2717
+ | ------------- | ---------------------------------- | -------- | --------- | ---------------------------------------- |
2718
+ | `onSearch` | `(q: string) => Promise<string[]>` | Yes | | 검색 콜백 |
2719
+ | `debounceMs` | `number` | | 300 | 디바운스 ms |
2720
+ | `minChars` | `number` | | 1 | 최소 검색 글자 수 |
2721
+ | `placeholder` | `string` | | "Search…" | 플레이스홀더 |
2722
+ | `onSelect` | `(value: string) => void` | | | 선택 콜백 |
2723
+ | `labels` | `AsyncComboboxLabels` | | | input/loading/noResults/placeholder 문구 |
2724
+ | `loadingText` | `string` | | | 로딩 문구. labels.loading 사용 권장 |
2725
+
2726
+ #### VerticalTabs
2727
+
2728
+ **Import:** `import { VerticalTabs } from "@reopt-ai/opt-ui"`
2729
+ **Dependencies:** tabs (core)
2730
+
2731
+ | Prop | Type | Required | Default | Description |
2732
+ | -------------- | ---------- | -------- | ------- | ----------------- |
2733
+ | `tabs` | `TabDef[]` | Yes | | 탭 정의 배열 |
2734
+ | `defaultTabId` | `string` | | | 기본 선택 탭 ID |
2735
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2736
+
2737
+ #### ColumnToggler
2738
+
2739
+ **Import:** `import { ColumnToggler } from "@reopt-ai/opt-ui"`
2740
+ **Dependencies:** popover (core), checkbox (core)
2741
+
2742
+ | Prop | Type | Required | Default | Description |
2743
+ | ---------------- | ------------------------------------ | -------- | ------- | ---------------------- |
2744
+ | `columns` | `ColumnTogglerColumn[]` | Yes | | 전체 컬럼 목록 |
2745
+ | `visibleColumns` | `string[]` | Yes | | 표시 중인 컬럼 ID 배열 |
2746
+ | `onChange` | `(visibleColumns: string[]) => void` | Yes | | 변경 콜백 |
2747
+
2748
+ #### TreeTable
2749
+
2750
+ **Import:** `import { TreeTable } from "@reopt-ai/opt-ui"`
2751
+ **Dependencies:** data-table (shells)
2752
+
2753
+ | Prop | Type | Required | Default | Description |
2754
+ | ----------------- | -------------------- | -------- | ------- | ------------------ |
2755
+ | `data` | `TreeNode<T>[]` | Yes | | 트리 노드 배열 |
2756
+ | `columns` | `TreeColumnDef<T>[]` | Yes | | 컬럼 정의 |
2757
+ | `defaultExpanded` | `string[]` | | [] | 기본 펼침 노드 ID |
2758
+ | `indentSize` | `number` | | 24 | 들여쓰기 크기 (px) |
2759
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2760
+
2761
+ #### InlineEditTable
2762
+
2763
+ **Import:** `import { InlineEditTable } from "@reopt-ai/opt-ui"`
2764
+ **Dependencies:** data-table (shells)
2765
+
2766
+ | Prop | Type | Required | Default | Description |
2767
+ | -------------- | ---------------------------------------------------------- | -------- | ------- | -------------------------------- |
2768
+ | `data` | `T[]` | Yes | | 행 데이터 배열 |
2769
+ | `columns` | `InlineEditColumnDef<T>[]` | Yes | | 컬럼 정의 (editable 플래그 포함) |
2770
+ | `keyExtractor` | `(row: T) => string` | Yes | | 행 키 추출기 |
2771
+ | `onCellEdit` | `(rowId: string, columnId: string, value: string) => void` | | | 셀 편집 확정 콜백 |
2772
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2773
+
2774
+ #### KanbanBoard
2775
+
2776
+ **Import:** `import { KanbanBoard } from "@reopt-ai/opt-ui"`
2777
+ **Dependencies:** scroll-area (core)
2778
+
2779
+ | Prop | Type | Required | Default | Description |
2780
+ | -------------- | ------------------------------------------- | -------- | ------- | -------------------------------- |
2781
+ | `columns` | `KanbanColumn<T>[]` | Yes | | 컬럼 목록 (각 컬럼에 items 배열) |
2782
+ | `onDragEnd` | `(itemId, fromCol, toCol, toIndex) => void` | Yes | | 드래그 완료 콜백 |
2783
+ | `renderCard` | `(item: T) => ReactNode` | Yes | | 카드 렌더링 함수 |
2784
+ | `keyExtractor` | `(item: T) => string` | Yes | | 항목 키 추출기 |
2785
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2786
+
2787
+ #### RichTextEditor
2788
+
2789
+ **Import:** `import { RichTextEditor } from "@reopt-ai/opt-ui"`
2790
+
2791
+ | Prop | Type | Required | Default | Description |
2792
+ | ------------- | ------------------------- | -------- | -------------------------------------------------------- | ----------------- |
2793
+ | `value` | `string` | Yes | | 텍스트 값 |
2794
+ | `onChange` | `(value: string) => void` | Yes | | 변경 콜백 |
2795
+ | `placeholder` | `string` | | "Write something…" | 플레이스홀더 |
2796
+ | `toolbar` | `ToolbarAction[]` | | ["bold","italic","code","link","heading","list","quote"] | 툴바 액션 목록 |
2797
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2798
+
2799
+ #### CodeDiffViewer
2800
+
2801
+ **Import:** `import { CodeDiffViewer } from "@reopt-ai/opt-ui"`
2802
+
2803
+ | Prop | Type | Required | Default | Description |
2804
+ | ----------------- | ---------------------- | -------- | --------- | --------------------------------------- |
2805
+ | `original` | `string` | Yes | | 원본 코드 |
2806
+ | `modified` | `string` | Yes | | 수정된 코드 |
2807
+ | `mode` | `"split" \| "unified"` | | "unified" | 뷰 모드 |
2808
+ | `showLineNumbers` | `boolean` | | true | 줄 번호 표시 |
2809
+ | `scrollLabel` | `string` | | | 스크롤 가능한 diff 영역의 접근성 레이블 |
2810
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2811
+
2812
+ #### WebhookConfig
2813
+
2814
+ **Import:** `import { WebhookConfig } from "@reopt-ai/opt-ui"`
2815
+ **Dependencies:** input (core), checkbox (core), number-input (core), button (core)
2816
+
2817
+ | Prop | Type | Required | Default | Description |
2818
+ | ----------------- | ------------------------------- | -------- | ------- | ----------------------- |
2819
+ | `webhook` | `WebhookDef` | Yes | | 웹훅 설정 객체 |
2820
+ | `onChange` | `(webhook: WebhookDef) => void` | Yes | | 변경 콜백 |
2821
+ | `availableEvents` | `string[]` | Yes | | 선택 가능한 이벤트 목록 |
2822
+ | `onTest` | `() => void` | | | 테스트 버튼 콜백 |
2823
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2824
+
2825
+ #### FeatureFlagPanel
2826
+
2827
+ **Import:** `import { FeatureFlagPanel } from "@reopt-ai/opt-ui"`
2828
+ **Dependencies:** switch (core), badge (core), number-input (core)
2829
+
2830
+ | Prop | Type | Required | Default | Description |
2831
+ | ----------------- | ---------------------------------------------- | -------- | ------- | ------------------ |
2832
+ | `flags` | `FeatureFlag[]` | Yes | | 피처 플래그 목록 |
2833
+ | `onToggle` | `(flagId: string, enabled: boolean) => void` | Yes | | 토글 콜백 |
2834
+ | `onRolloutChange` | `(flagId: string, percentage: number) => void` | | | 롤아웃 % 변경 콜백 |
2835
+ | `environments` | `string[]` | Yes | | 전체 환경 목록 |
2836
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2837
+
2838
+ #### DataImportWizard
2839
+
2840
+ **Import:** `import { DataImportWizard } from "@reopt-ai/opt-ui"`
2841
+ **Dependencies:** button (core)
2842
+
2843
+ | Prop | Type | Required | Default | Description |
2844
+ | ----------------- | ------------------------- | -------- | ------- | ------------------- |
2845
+ | `fields` | `ImportFieldDef[]` | Yes | | 매핑 대상 필드 목록 |
2846
+ | `onImport` | `(mapping, data) => void` | Yes | | 임포트 확정 콜백 |
2847
+ | `acceptedFormats` | `string` | | ".csv" | 허용 파일 형식 |
2848
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2849
+
2850
+ #### MegaMenu
2851
+
2852
+ **Import:** `import { MegaMenu } from "@reopt-ai/opt-ui"`
2853
+ **Dependencies:** popover (core)
2854
+
2855
+ | Prop | Type | Required | Default | Description |
2856
+ | -------------- | ------------------- | -------- | ------- | ------------------ |
2857
+ | `menus` | `MegaMenuSection[]` | Yes | | 메뉴 섹션 배열 |
2858
+ | `columns` | `number` | | 3 | 그리드 컬럼 수 |
2859
+ | `footer` | `ReactNode` | | | 하단 footer 슬롯 |
2860
+ | `triggerLabel` | `string` | | "Menu" | 트리거 버튼 텍스트 |
2861
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2862
+
2863
+ #### BulkActions
2864
+
2865
+ **Import:** `import { BulkActions } from "@reopt-ai/opt-ui"`
2866
+ **Dependencies:** dropdown-menu (core), badge (core)
2867
+
2868
+ | Prop | Type | Required | Default | Description |
2869
+ | --------------- | ---------------------------- | -------- | ------- | -------------------------------------------- |
2870
+ | `selectedCount` | `number` | Yes | | 선택된 항목 수 |
2871
+ | `actions` | `BulkActionDef[]` | Yes | | 액션 목록. { id, label, variant?: "danger" } |
2872
+ | `onAction` | `(actionId: string) => void` | Yes | | 액션 실행 콜백 |
2873
+ | `onClear` | `() => void` | Yes | | 선택 해제 콜백 |
2874
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2875
+
2876
+ #### SavedFilters
2877
+
2878
+ **Import:** `import { SavedFilters } from "@reopt-ai/opt-ui"`
2879
+ **Dependencies:** popover (core), input (core)
2880
+
2881
+ | Prop | Type | Required | Default | Description |
2882
+ | ---------------- | ---------------------------------------------------------- | -------- | ------- | -------------------- |
2883
+ | `currentFilters` | `Record<string, unknown>` | Yes | | 현재 적용 중인 필터 |
2884
+ | `presets` | `FilterPreset[]` | Yes | | 저장된 프리셋 목록 |
2885
+ | `onSavePreset` | `(name: string, filters: Record<string, unknown>) => void` | Yes | | 프리셋 저장 콜백 |
2886
+ | `onLoadPreset` | `(preset: FilterPreset) => void` | Yes | | 프리셋 불러오기 콜백 |
2887
+ | `onDeletePreset` | `(presetId: string) => void` | Yes | | 프리셋 삭제 콜백 |
2888
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2889
+
2890
+ #### NotificationCenter
2891
+
2892
+ **Import:** `import { NotificationCenter } from "@reopt-ai/opt-ui"`
2893
+ **Dependencies:** popover (core), badge (core), scroll-area (core)
2894
+
2895
+ | Prop | Type | Required | Default | Description |
2896
+ | --------------- | ---------------------- | -------- | ------- | ------------------- |
2897
+ | `notifications` | `NotificationItem[]` | Yes | | 알림 목록 |
2898
+ | `onMarkRead` | `(id: string) => void` | Yes | | 읽음 처리 콜백 |
2899
+ | `onMarkAllRead` | `() => void` | Yes | | 전체 읽음 처리 콜백 |
2900
+ | `onAction` | `(id: string) => void` | | | 알림 액션 콜백 |
2901
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2902
+
2903
+ #### AuditLog
2904
+
2905
+ **Import:** `import { AuditLog } from "@reopt-ai/opt-ui"`
2906
+ **Dependencies:** avatar (core), badge (core)
2907
+
2908
+ | Prop | Type | Required | Default | Description |
2909
+ | ------------ | -------------- | -------- | ------- | ------------------- |
2910
+ | `entries` | `AuditEntry[]` | Yes | | 감사 로그 항목 배열 |
2911
+ | `onLoadMore` | `() => void` | | | 더 보기 콜백 |
2912
+ | `loading` | `boolean` | | false | 로딩 상태 |
2913
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2914
+
2915
+ #### AuditTimeline
2916
+
2917
+ **Import:** `import { AuditTimeline } from "@reopt-ai/opt-ui"`
2918
+ **Dependencies:** badge (core), button (core), empty-state (core)
2919
+
2920
+ | Prop | Type | Required | Default | Description |
2921
+ | -------------- | ----------------------------- | -------- | ------- | ---------------------- |
2922
+ | `entries` | `AuditEntry[]` | Yes | | 변경 이력 항목 배열 |
2923
+ | `labels` | `AuditTimelineLabels` | | | UI 텍스트 커스터마이징 |
2924
+ | `onEntryClick` | `(entry: AuditEntry) => void` | | | 항목 클릭 콜백 |
2925
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2926
+
2927
+ #### ChatSidebar
2928
+
2929
+ **Import:** `import { ChatSidebar } from "@reopt-ai/opt-ui"`
2930
+ **Dependencies:** button (core), input (core), scroll-area (core), empty-state (core)
2931
+
2932
+ | Prop | Type | Required | Default | Description |
2933
+ | ---------------------- | --------------------------------------------- | -------- | ------- | --------------------------------------------------------------- |
2934
+ | `conversations` | `ChatConversationDef[]` | Yes | | 대화 목록 배열. { id, title, lastMessage?, timestamp, unread? } |
2935
+ | `activeConversationId` | `string` | | | 현재 활성 대화 ID |
2936
+ | `onConversationSelect` | `(conversation: ChatConversationDef) => void` | | | 대화 선택 핸들러 |
2937
+ | `onNewChat` | `() => void` | | | 새 대화 생성 핸들러 |
2938
+ | `onSearch` | `(query: string) => void` | | | 검색 핸들러 |
2939
+ | `labels` | `ChatSidebarLabels` | | | i18n 라벨 오버라이드 |
2940
+
2941
+ #### ChatInput
2942
+
2943
+ **Import:** `import { ChatInput } from "@reopt-ai/opt-ui"`
2944
+ **Dependencies:** button (core), kbd (core), select (core)
2945
+
2946
+ | Prop | Type | Required | Default | Description |
2947
+ | -------------- | --------------------------- | -------- | ------- | -------------------------- |
2948
+ | `value` | `string` | | | 제어 모드: 입력 값 |
2949
+ | `onSend` | `(message: string) => void` | | | 메시지 전송 핸들러 |
2950
+ | `onFileAttach` | `() => void` | | | 파일 첨부 클릭 핸들러 |
2951
+ | `models` | `ChatModelDef[]` | | | 모델 선택 옵션 |
2952
+ | `stylePresets` | `ChatStylePresetDef[]` | | | 스타일 프리셋 옵션 |
2953
+ | `maxRows` | `number` | | 6 | textarea 최대 행 수 |
2954
+ | `showHint` | `boolean` | | true | Shift+Enter 힌트 표시 여부 |
2955
+ | `labels` | `ChatInputLabels` | | | i18n 라벨 오버라이드 |
2956
+
2957
+ **Examples:**
2958
+
2959
+ _채팅 입력:_
2960
+
2961
+ ```tsx
2962
+ import { ChatInput } from "@reopt-ai/opt-ui";
2963
+
2964
+ <ChatInput
2965
+ placeholder="메시지를 입력하세요..."
2966
+ onSend={(message) => console.log(message)}
2967
+ />;
2968
+ ```
2969
+
2970
+ #### ChatMessageList
2971
+
2972
+ **Import:** `import { ChatMessageList } from "@reopt-ai/opt-ui"`
2973
+ **Dependencies:** scroll-area (core), avatar (core), empty-state (core)
2974
+
2975
+ | Prop | Type | Required | Default | Description |
2976
+ | ----------------- | ---------------------------------------- | -------- | ------- | --------------------------------------------- |
2977
+ | `messages` | `ChatMessageDef[]` | Yes | | 메시지 배열. { id, role, content, timestamp } |
2978
+ | `loading` | `boolean` | | false | 타이핑 인디케이터 표시 |
2979
+ | `renderContent` | `(message: ChatMessageDef) => ReactNode` | | | 커스텀 메시지 렌더러. 기본: plain text |
2980
+ | `assistantAvatar` | `string` | | | 어시스턴트 아바타 이미지 URL |
2981
+ | `showTimestamps` | `boolean` | | true | 타임스탬프 표시 여부 |
2982
+ | `autoScroll` | `boolean` | | true | 새 메시지 시 자동 스크롤 |
2983
+ | `labels` | `ChatMessageListLabels` | | | i18n 라벨 오버라이드 |
2984
+
2985
+ **Examples:**
2986
+
2987
+ _메시지 목록:_
2988
+
2989
+ ```tsx
2990
+ import { ChatMessageList } from "@reopt-ai/opt-ui";
2991
+
2992
+ const messages = [
2993
+ { id: "1", role: "user", content: "안녕하세요!", timestamp: new Date() },
2994
+ { id: "2", role: "assistant", content: "반갑습니다.", timestamp: new Date() },
2995
+ ];
2996
+
2997
+ <ChatMessageList messages={messages} loading={false} />;
2998
+ ```
2999
+
3000
+ ### Surface Layer