@reopt-ai/opt-ui 1.10.0 → 1.12.0

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 (73) hide show
  1. package/COMPONENT_CATALOG.md +522 -218
  2. package/README.md +61 -7
  3. package/dist/core/index.cjs +10 -8
  4. package/dist/core/index.d.cts +3 -3
  5. package/dist/core/index.d.ts +3 -3
  6. package/dist/core/index.js +3 -3
  7. package/dist/docs/02-components/01-core.md +213 -96
  8. package/dist/docs/02-components/02-visuals.md +1 -1
  9. package/dist/docs/02-components/03-shells.md +334 -123
  10. package/dist/docs/02-components/04-surfaces.md +1 -1
  11. package/dist/docs/02-components/index.md +5 -5
  12. package/dist/docs/03-recipes/02-dashboards.md +126 -10
  13. package/dist/{field-sidebar-B6Ndr8HE.cjs → field-sidebar-BYgEmdy0.cjs} +2128 -1558
  14. package/dist/{field-sidebar-BXjvV7Cz.js → field-sidebar-BuO37l4c.js} +2111 -1561
  15. package/dist/{field-sidebar-nwcE9LC4.d.cts → field-sidebar-CrYlRZew.d.ts} +375 -154
  16. package/dist/{field-sidebar-DWfJAJlx.d.ts → field-sidebar-uXmoyvd7.d.cts} +375 -154
  17. package/dist/id-registry.cjs +124 -12
  18. package/dist/id-registry.d.cts +1 -2
  19. package/dist/id-registry.d.ts +1 -2
  20. package/dist/id-registry.js +124 -14
  21. package/dist/id-registry.json +265 -31
  22. package/dist/index.cjs +1162 -253
  23. package/dist/index.d.cts +573 -60
  24. package/dist/index.d.ts +573 -60
  25. package/dist/index.js +1134 -242
  26. package/dist/{key-pad-menu-DfZbeXhG.d.cts → key-pad-menu-CwcY_Vps.d.cts} +151 -7
  27. package/dist/{key-pad-menu-BQunU20e.js → key-pad-menu-Di2aRGbM.js} +388 -461
  28. package/dist/{key-pad-menu-D5mQcS5v.cjs → key-pad-menu-SItoHPLu.cjs} +490 -609
  29. package/dist/{key-pad-menu-BsgJMjD4.d.ts → key-pad-menu-WBJShCJn.d.ts} +152 -8
  30. package/dist/meta.cjs +1304 -168
  31. package/dist/meta.d.cts +12 -36
  32. package/dist/meta.d.ts +12 -36
  33. package/dist/meta.js +1304 -170
  34. package/dist/query.d.cts +1 -2
  35. package/dist/query.d.ts +1 -2
  36. package/dist/query.js +0 -2
  37. package/dist/shells/index.cjs +4 -1
  38. package/dist/shells/index.d.cts +2 -2
  39. package/dist/shells/index.d.ts +2 -2
  40. package/dist/shells/index.js +2 -2
  41. package/dist/{text-truncate-BGr7bB_8.d.cts → text-truncate-CQyfUZvq.d.cts} +48 -5
  42. package/dist/{text-truncate-BGr7bB_8.d.ts → text-truncate-CQyfUZvq.d.ts} +48 -5
  43. package/dist/{text-truncate-j6X3z7Pv.js → text-truncate-DSuZECy0.js} +446 -94
  44. package/dist/{text-truncate-CxdzAnhS.cjs → text-truncate-I1XLWmRa.cjs} +522 -90
  45. package/dist/theme/server.d.cts +1 -2
  46. package/dist/theme/server.d.ts +1 -2
  47. package/dist/theme/server.js +0 -2
  48. package/dist/visuals/index.js +0 -1
  49. package/package.json +4 -3
  50. package/dist/field-sidebar-BXjvV7Cz.js.map +0 -1
  51. package/dist/field-sidebar-DWfJAJlx.d.ts.map +0 -1
  52. package/dist/field-sidebar-nwcE9LC4.d.cts.map +0 -1
  53. package/dist/id-registry.d.cts.map +0 -1
  54. package/dist/id-registry.d.ts.map +0 -1
  55. package/dist/id-registry.js.map +0 -1
  56. package/dist/index.d.cts.map +0 -1
  57. package/dist/index.d.ts.map +0 -1
  58. package/dist/index.js.map +0 -1
  59. package/dist/key-pad-menu-BQunU20e.js.map +0 -1
  60. package/dist/key-pad-menu-BsgJMjD4.d.ts.map +0 -1
  61. package/dist/key-pad-menu-DfZbeXhG.d.cts.map +0 -1
  62. package/dist/meta.d.cts.map +0 -1
  63. package/dist/meta.d.ts.map +0 -1
  64. package/dist/meta.js.map +0 -1
  65. package/dist/query.d.cts.map +0 -1
  66. package/dist/query.d.ts.map +0 -1
  67. package/dist/query.js.map +0 -1
  68. package/dist/text-truncate-BGr7bB_8.d.cts.map +0 -1
  69. package/dist/text-truncate-BGr7bB_8.d.ts.map +0 -1
  70. package/dist/text-truncate-j6X3z7Pv.js.map +0 -1
  71. package/dist/theme/server.d.cts.map +0 -1
  72. package/dist/theme/server.d.ts.map +0 -1
  73. package/dist/theme/server.js.map +0 -1
@@ -2,17 +2,17 @@
2
2
 
3
3
  <!-- DEPRECATED: Prefer dist/docs/02-components/ for per-layer reference. -->
4
4
  <!-- Auto-generated from ComponentMeta. Do not edit. -->
5
- <!-- Version: 1.9.0 -->
5
+ <!-- Version: 1.12.0 -->
6
6
 
7
7
  ## Quick Stats
8
8
 
9
9
  | Layer | Count |
10
10
  | --------- | ------- |
11
- | Core | 68 |
11
+ | Core | 74 |
12
12
  | Visuals | 0 |
13
- | Shells | 80 |
13
+ | Shells | 86 |
14
14
  | Surfaces | 0 |
15
- | **Total** | **148** |
15
+ | **Total** | **160** |
16
16
 
17
17
  ## Component Selection Guide
18
18
 
@@ -95,7 +95,7 @@
95
95
  | 인사이트/이상탐지 | InsightsPanel | Shell |
96
96
  | 프롬프트 템플릿 | PromptTemplate | Shell |
97
97
 
98
- ## Core Components (68)
98
+ ## Core Components (74)
99
99
 
100
100
  ### Input
101
101
 
@@ -137,7 +137,7 @@
137
137
  | Card | 범용 카드 컨테이너. Header, Title, Description, Content, Footer 하위 컴포넌트 포함. | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardContent`, `CardFooter` |
138
138
  | Breadcrumb | 현재 위치를 표시하고 계층 탐색을 제공하는 컴포넌트. | `Breadcrumb` |
139
139
  | EmptyState | 데이터가 없을 때 표시하는 빈 상태 컴포넌트. 아이콘, 제목, 설명, 액션 버튼 지원. | `EmptyState` |
140
- | StatCard | 트렌드 방향과 변화량을 표시하는 통계 카드. | `StatCard` |
140
+ | StatCard | 단일 지표를 값·변화량·보조 설명으로 표시하는 통계 카드. 비교 기준이 없으면 변화량 줄을 렌더하지 않는다. | `StatCard` |
141
141
  | Logo | 아이콘+텍스트 조합, 이미지, 링크 래핑을 지원하는 로고 컴포넌트. Sidebar 등에서 활용. | `Logo` |
142
142
 
143
143
  ### Navigation & Overlay
@@ -175,37 +175,43 @@
175
175
 
176
176
  ### Other
177
177
 
178
- | Component | Description | Key Exports |
179
- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
180
- | FieldToken | 필드 타입을 글리프 하나로 표현하는 토큰. 문자열·숫자·날짜·IP·지오 등 분석 스키마 타입마다 고정된 아이콘과 팔레트 슬롯을 부여해 필드 목록·컬럼 헤더·속성 테이블 전역에서 같은 어휘를 쓴다. | `FieldToken`, `FIELD_TYPE_TOKENS`, `resolveFieldType` |
181
- | Facet | 필드 값 분포를 카운트와 점유율 막대로 보여주고 그 행 자체가 필터가 되는 패싯. 긴 꼬리는 접어 두고 상위 값부터 읽힌다. | `Facet`, `FacetGroup` |
182
- | Expression | 조건을 폼이 아니라 문장으로 쓰고 그 자리에서 편집하는 표현식 절. 알림 규칙·세그먼트 필터처럼 읽어서 검증해야 하는 조건에 쓴다. | `Expression`, `ExpressionGroup` |
183
- | TextTruncate | 실제 폰트로 실제 가용 폭을 측정해 문자열의 식별력이 가장 낮은 부분을 잘라내는 생략. CSS가 못 하는 앞·중간·양끝 생략을 지원하고 전체 문자열은 접근성 트리에 남는다. | `TextTruncate` |
184
- | Highlight | 검색어에 해당하는 구간을 <mark>로 표시. 긴 항목 우선 매칭이라 겹치는 검색어도 조각나지 않는다. | `Highlight` |
185
- | LiveRegion | 라이브 뷰의 변화를 스크린 리더에 읽어 주는 영역. 스로틀로 폭주를 요약하고 두 노드를 번갈아 써서 같은 문구도 다시 읽힌다. | `LiveRegion` |
186
- | ColorPalette | 시각화 색 팔레트를 그 팔레트의 모습 그대로 보여 주고 고르게 하는 컴포넌트. 범주형은 블록, 순차·발산형은 그라디언트로 그려 데이터 종류를 그림이 말한다. | `ColorPaletteDisplay`, `ColorPalettePicker`, `THEME_PALETTES` |
187
- | InlineEdit | 대시보드 제목·지표 이름처럼 읽히는 횟수가 훨씬 많은 값을 그 자리에서 고치는 편집. Enter 확정, Escape 되돌리기, 거절된 저장은 입력을 유지한다. | `InlineEdit` |
188
- | KeyPadMenu | 이름보다 그림으로 알아보기 쉬운 선택지를 타일로 고르는 메뉴. 내부는 실제 radio·checkbox라 키보드와 스크린 리더가 그대로 동작한다. | `KeyPadMenu` |
189
- | Text | 본문, 레이블, 보조 설명, 코드에 일관된 의미 기반 타이포그래피를 적용합니다. | `Text` |
190
- | Heading | 문서의 의미 계층과 시각적 타이포그래피 계층을 독립적으로 제어합니다. | `Heading` |
191
- | Separator | 콘텐츠를 구분하는 가로/세로 디바이더. 라벨을 넣으면 가운데 정렬 구분선이 된다. | `Separator` |
192
- | OtpField | 일회용 코드(OTP)/PIN 입력. 셀 단위 입력, 붙여넣기 분배, 자동 포커스 이동, 백스페이스 네비게이션과 폼 이름/오류 연결을 지원합니다. | `OtpField` |
193
- | Toggle | 눌림(pressed) 두 상태 버튼. 단독 사용하거나 ToggleGroup으로 묶어 단일/다중 선택을 만든다. | `Toggle`, `ToggleGroup` |
194
- | Accordion | 수직으로 쌓인 펼침/접힘 패널. single(한 개)/multiple(여러 개) 모드와 collapsible 지원. | `AccordionRoot`, `AccordionItem`, `AccordionTrigger`, `AccordionContent` |
195
- | Meter | 범위 내 스칼라 측정값 게이지 (디스크 사용량·점수·용량 등). role=meter로 작업 진행률(Progress)과 구분된다. | `Meter` |
196
- | BlockLayout | Block 루트 레이아웃. 자식 section spacing과 선택적 시맨틱 inset을 제공하고 loading prop으로 LoadingOverlay를 자동 래핑합니다. | `BlockLayout` |
197
- | createBlock | Block 팩토리 함수. BlockLayout 래핑을 구조적으로 강제하여 loading/className 처리를 자동화합니다. | `createBlock` |
198
- | StarRating | 1~N점 별점을 선택하는 인터랙티브 레이팅 입력. 읽기 전용 표시도 지원. | `StarRating` |
199
- | ErrorBoundary | React 에러 바운더리. 자식 컴포넌트 렌더 에러를 잡아 fallback UI를 표시합니다. | `ErrorBoundary` |
200
- | Command | cmdk 스타일 명령 anatomy. 자동 필터링 + 키보드 내비게이션. 인라인 또는 CommandDialog로 사용. | `Command`, `CommandDialog`, `CommandInput`, `CommandList`, `CommandEmpty`, `CommandGroup`, `CommandItem`, `CommandSeparator`, `CommandShortcut` |
201
- | ShaderSurface | ogl 기반 애니메이션 WebGL 셰이더 배경. 럭셔리 프리셋(메탈릭/실크/유리 등) + 색·파라미터로 배경·카드 배경을 만든다. 정지 프레임·PNG 캡처·WebGL 폴백 지원. | `ShaderSurface` |
178
+ | Component | Description | Key Exports |
179
+ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
180
+ | FieldToken | 필드 타입을 글리프 하나로 표현하는 토큰. 문자열·숫자·날짜·IP·지오 등 분석 스키마 타입마다 고정된 아이콘과 팔레트 슬롯을 부여해 필드 목록·컬럼 헤더·속성 테이블 전역에서 같은 어휘를 쓴다. | `FieldToken`, `FIELD_TYPE_TOKENS`, `resolveFieldType` |
181
+ | Facet | 필드 값 분포를 카운트와 점유율 막대로 보여주고 그 행 자체가 필터가 되는 패싯. 긴 꼬리는 접어 두고 상위 값부터 읽힌다. | `Facet`, `FacetGroup` |
182
+ | Expression | 조건을 폼이 아니라 문장으로 쓰고 그 자리에서 편집하는 표현식 절. 알림 규칙·세그먼트 필터처럼 읽어서 검증해야 하는 조건에 쓴다. | `Expression`, `ExpressionGroup` |
183
+ | TextTruncate | 실제 폰트로 실제 가용 폭을 측정해 문자열의 식별력이 가장 낮은 부분을 잘라내는 생략. CSS가 못 하는 앞·중간·양끝 생략을 지원하고 전체 문자열은 접근성 트리에 남는다. | `TextTruncate` |
184
+ | Highlight | 검색어에 해당하는 구간을 <mark>로 표시. 긴 항목 우선 매칭이라 겹치는 검색어도 조각나지 않는다. | `Highlight` |
185
+ | LiveRegion | 라이브 뷰의 변화를 스크린 리더에 읽어 주는 영역. 스로틀로 폭주를 요약하고 두 노드를 번갈아 써서 같은 문구도 다시 읽힌다. | `LiveRegion` |
186
+ | ColorPalette | 시각화 색 팔레트를 그 팔레트의 모습 그대로 보여 주고 고르게 하는 컴포넌트. 범주형은 블록, 순차·발산형은 그라디언트로 그려 데이터 종류를 그림이 말한다. | `ColorPaletteDisplay`, `ColorPalettePicker`, `THEME_PALETTES` |
187
+ | InlineEdit | 대시보드 제목·지표 이름처럼 읽히는 횟수가 훨씬 많은 값을 그 자리에서 고치는 편집. Enter 확정, Escape 되돌리기, 거절된 저장은 입력을 유지한다. | `InlineEdit` |
188
+ | KeyPadMenu | 이름보다 그림으로 알아보기 쉬운 선택지를 타일로 고르는 메뉴. 내부는 실제 radio·checkbox라 키보드와 스크린 리더가 그대로 동작한다. | `KeyPadMenu` |
189
+ | Text | 본문, 레이블, 보조 설명, 코드에 일관된 의미 기반 타이포그래피를 적용합니다. | `Text` |
190
+ | Heading | 문서의 의미 계층과 시각적 타이포그래피 계층을 독립적으로 제어합니다. | `Heading` |
191
+ | Separator | 콘텐츠를 구분하는 가로/세로 디바이더. 라벨을 넣으면 가운데 정렬 구분선이 된다. | `Separator` |
192
+ | OtpField | 일회용 코드(OTP)/PIN 입력. 셀 단위 입력, 붙여넣기 분배, 자동 포커스 이동, 백스페이스 네비게이션과 폼 이름/오류 연결을 지원합니다. | `OtpField` |
193
+ | Toggle | 눌림(pressed) 두 상태 버튼. 단독 사용하거나 ToggleGroup으로 묶어 단일/다중 선택을 만든다. | `Toggle`, `ToggleGroup` |
194
+ | Accordion | 수직으로 쌓인 펼침/접힘 패널. single(한 개)/multiple(여러 개) 모드와 collapsible 지원. | `AccordionRoot`, `AccordionItem`, `AccordionTrigger`, `AccordionContent` |
195
+ | Meter | 범위 내 스칼라 측정값 게이지 (디스크 사용량·점수·용량 등). role=meter로 작업 진행률(Progress)과 구분된다. | `Meter` |
196
+ | DescriptionList | 대상의 라벨 있는 사실들을 시맨틱 <dl>로 표시한다. 상세 패널의 필드 나열을 표준화하고 식별자 복사를 제공한다. | `DescriptionList` |
197
+ | Identity | 사람(또는 익명 디바이스)을 목록 칸으로 표현한다. 이름→이메일→ID 폴백과 익명 표식을 한 곳에서 처리한다. | `Identity` |
198
+ | BlockLayout | Block 루트 레이아웃. 자식 section spacing과 선택적 시맨틱 inset을 제공하고 loading prop으로 LoadingOverlay를 자동 래핑합니다. | `BlockLayout` |
199
+ | createBlock | Block 팩토리 함수. BlockLayout 래핑을 구조적으로 강제하여 loading/className 처리를 자동화합니다. | `createBlock` |
200
+ | StarRating | 1~N점 별점을 선택하는 인터랙티브 레이팅 입력. 읽기 전용 표시도 지원. | `StarRating` |
201
+ | ErrorBoundary | React 에러 바운더리. 자식 컴포넌트 렌더 에러를 잡아 fallback UI를 표시합니다. | `ErrorBoundary` |
202
+ | Command | cmdk 스타일 명령 anatomy. 자동 필터링 + 키보드 내비게이션. 인라인 또는 CommandDialog로 사용. | `Command`, `CommandDialog`, `CommandInput`, `CommandList`, `CommandEmpty`, `CommandGroup`, `CommandItem`, `CommandSeparator`, `CommandShortcut` |
203
+ | ShaderSurface | ogl 기반 애니메이션 WebGL 셰이더 배경. 럭셔리 프리셋(메탈릭/실크/유리 등) + 색·파라미터로 배경·카드 배경을 만든다. 정지 프레임·PNG 캡처·WebGL 폴백 지원. | `ShaderSurface` |
204
+ | Callout | 페이지에 머무는 인페이지 고지. Alert와 달리 dismiss가 없고, 조건이 참인 동안 레이아웃의 일부로 남습니다. | `Callout` |
205
+ | StatusDot | 점 + 텍스트로 상태를 표현합니다. 라벨이 필수라 색만으로 상태를 말할 수 없습니다. | `StatusDot` |
206
+ | CopyButton | 값을 클립보드에 올리고 성공 여부를 알립니다. 클립보드 거부를 삼키지 않습니다. | `CopyButton` |
207
+ | SegmentedControl | 선택지를 모두 보여주는 단일 선택 컨트롤. radio-group 프리미티브 위에 올려 화살표 키가 동작합니다. | `SegmentedControl` |
202
208
 
203
209
  ## Visual Components (0)
204
210
 
205
211
  | Component | Description | Key Exports |
206
212
  | --------- | ----------- | ----------- |
207
213
 
208
- ## Shell Components (80)
214
+ ## Shell Components (86)
209
215
 
210
216
  ### Navigation & Layout
211
217
 
@@ -337,20 +343,26 @@
337
343
 
338
344
  ### Other
339
345
 
340
- | Component | Description | Key Exports |
341
- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
342
- | PageAside | Sticky 페이지 사이드 aside chrome. 고정 너비 + header/body/footer 3-slot. | `PageAside` |
343
- | FailureList | 실패 목록 패널. severity별 색상 강조, 그룹핑, 액션 슬롯을 지원합니다. | `FailureList` |
344
- | KeyValueEditor | 키-값 쌍 편집기. 동적 행 추가/삭제, 비밀값 토글, 유효성 검사를 지원합니다. | `KeyValueEditor` |
345
- | AuditTimeline | 변경 이력 타임라인. 액션별 색상 코딩 + 확장 가능한 diff 뷰. | `AuditTimeline` |
346
- | ChatSidebar | AI 채팅 사이드바. 대화 목록, 검색, 대화 버튼. | `ChatSidebar` |
347
- | ChatInput | 채팅 입력 컴포넌트. 자동 리사이즈 textarea, 파일 첨부, 모델/스타일 Select. | `ChatInput` |
348
- | ChatMessageList | 채팅 메시지 목록. 역할별 말풍선, 타이핑 인디케이터, 자동 스크롤. | `ChatMessageList` |
349
- | TimeRangeControl | date math(now-7d, now/d) 기반 시간 범위 컨트롤. quick select, 프리셋/최근 사용, 명시적 Update, 자동 갱신, 창 이동·확대/축소 버튼을 제공합니다. | `TimeRangeControl`, `DEFAULT_TIME_PRESETS` |
350
- | TimeSeriesPanel | 시간 범위 컨트롤과 시계열 차트를 단위로 묶은 패널. 드래그 줌과 줌 히스토리(되돌리기), 범례 토글을 포함합니다. | `TimeSeriesPanel` |
351
- | LogTable | 계속 도착하는 로그용 윈도잉 테이블. 컬럼 정의 기반, 상단 삽입 시 스크롤 위치 보존, follow 상태 보고, 셀 값 즉시 필터, 밀도·정렬을 지원합니다. | `LogTable` |
352
- | QueryBar | 검색과 필터를 입력으로 합친 쿼리 바. field:value, -부정, (a or b), 비교 연산, 필드·값 자동완성, 절(clause) 칩을 지원합니다. | `QueryBar` |
353
- | FieldSidebar | 데이터에 어떤 필드가 있고 필드가 무슨 값을 갖는지 보여주는 사이드바. 분포 막대, 컬럼으로 승격, 값 기준 포함/제외 필터를 제공합니다. | `FieldSidebar` |
346
+ | Component | Description | Key Exports |
347
+ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
348
+ | PageAside | Sticky 페이지 사이드 aside chrome. 고정 너비 + header/body/footer 3-slot. | `PageAside` |
349
+ | FailureList | 실패 목록 패널. severity별 색상 강조, 그룹핑, 액션 슬롯을 지원합니다. | `FailureList` |
350
+ | KeyValueEditor | 키-값 쌍 편집기. 동적 행 추가/삭제, 비밀값 토글, 유효성 검사를 지원합니다. | `KeyValueEditor` |
351
+ | EventTimeline | 이벤트를 순서로 읽히게 하는 타임라인. 인접 이벤트 사이의 경과 시간을 라벨링하고, 속성 페이로드를 제자리에서 펼치며, 세션 단위 그룹핑을 지원한다. | `EventTimeline` |
352
+ | ScoreBreakdown | 합성 점수를 축별로 분해해 보여준다. 총점과 함께 축의 값·가중치·의미를 노출해 '43'을 판정이 아니라 발견으로 만든다. | `ScoreBreakdown` |
353
+ | Flyout | 목록을 화면에 레코드를 옆에서 보여주는 상세 패널. 모달이 아니다 — 포커스 트랩·aria-modal·inert 없이 Escape로 닫고 포커스를 되돌린다. | `Flyout` |
354
+ | AuditTimeline | 변경 이력 타임라인. 액션별 색상 코딩 + 확장 가능한 diff 뷰. | `AuditTimeline` |
355
+ | ChatSidebar | AI 채팅 사이드바. 대화 목록, 검색, 대화 버튼. | `ChatSidebar` |
356
+ | ChatInput | 채팅 입력 컴포넌트. 자동 리사이즈 textarea, 파일 첨부, 모델/스타일 Select. | `ChatInput` |
357
+ | ChatMessageList | 채팅 메시지 목록. 역할별 말풍선, 타이핑 인디케이터, 자동 스크롤. | `ChatMessageList` |
358
+ | TimeRangeControl | date math(now-7d, now/d) 기반 시간 범위 컨트롤. quick select, 프리셋/최근 사용, 명시적 Update, 자동 갱신, 이동·확대/축소 버튼을 제공합니다. | `TimeRangeControl`, `DEFAULT_TIME_PRESETS` |
359
+ | TimeSeriesPanel | 시간 범위 컨트롤과 시계열 차트를 단위로 묶은 패널. 드래그 줌과 히스토리(되돌리기), 범례 토글을 포함합니다. | `TimeSeriesPanel` |
360
+ | LogTable | 계속 도착하는 로그용 윈도잉 테이블. 컬럼 정의 기반, 상단 삽입 시 스크롤 위치 보존, follow 상태 보고, 셀 값 즉시 필터, 밀도·정렬을 지원합니다. | `LogTable` |
361
+ | QueryBar | 검색과 필터를 한 입력으로 합친 쿼리 바. field:value, -부정, (a or b), 비교 연산, 필드·값 자동완성, 절(clause) 칩을 지원합니다. | `QueryBar` |
362
+ | FieldSidebar | 데이터에 어떤 필드가 있고 각 필드가 무슨 값을 갖는지 보여주는 사이드바. 값 분포 막대, 컬럼으로 승격, 값 기준 포함/제외 필터를 제공합니다. | `FieldSidebar` |
363
+ | InspectorLayout | 목록과 인스펙터의 2-pane 레이아웃. 넓으면 밀어내고(push) 좁으면 덮으며(overlay), 닫을 때 포커스를 열었던 자리로 되돌립니다. | `InspectorLayout` |
364
+ | QueryFilterBar | QueryBar와 필터 버튼이 하나의 Query를 공유합니다. 버튼은 상태를 갖지 않고 Query를 읽어 활성 여부를 계산합니다. | `QueryFilterBar`, `hasActiveQuery` |
365
+ | CatalogFrame | 카탈로그 목록의 공통 뼈대. 헤더·통계·고지·필터·인스펙터·페이지네이션·일괄 작업과 빈/에러 상태를 담고, 필터나 페이지가 바뀌면 선택을 비웁니다. | `CatalogFrame`, `CatalogRowActions`, `CatalogCellControls` |
354
366
 
355
367
  ## Surface Components (0)
356
368
 
@@ -555,11 +567,11 @@
555
567
 
556
568
  **Import:** `import { Heading } from "@reopt-ai/opt-ui"`
557
569
 
558
- | Prop | Type | Required | Default | Description |
559
- | ---------- | ------------------------------------------------------------------------ | -------- | ------- | ------------------------ |
560
- | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | | | 의미 기반 HTML 제목 레벨 |
561
- | `variant` | `"heading-1" "heading-6" \| "display-1" \| "display-2" \| "display-3"` | | | 시각적 제목 역할 |
562
- | `children` | `ReactNode` | | | 제목 콘텐츠 |
570
+ | Prop | Type | Required | Default | Description |
571
+ | ---------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | ------------------------ |
572
+ | `level` | `1 \| 2 \| 3 \| 4 \| 5 \| 6` | | | 의미 기반 HTML 제목 레벨 |
573
+ | `variant` | `"heading-1" \| "heading-2" \| "heading-3" \| "heading-4" \| "heading-5" \| "heading-6" \| "display-1" \| "display-2" \| "display-3"` | | | 시각적 제목 역할 |
574
+ | `children` | `ReactNode` | | | 제목 콘텐츠 |
563
575
 
564
576
  #### Kbd
565
577
 
@@ -670,12 +682,21 @@
670
682
 
671
683
  **Import:** `import { StatCard } from "@reopt-ai/opt-ui"`
672
684
 
673
- | Prop | Type | Required | Default | Description |
674
- | -------- | ----------------------------- | -------- | ------- | ------------------------------- |
675
- | `title` | `string` | Yes | | 통계 제목 |
676
- | `value` | `string` | Yes | | 통계 값 |
677
- | `change` | `string` | Yes | | 변화량 텍스트 (예: '+12.5%') |
678
- | `trend` | `"up" \| "down" \| "neutral"` | Yes | | 트렌드 방향. 색상과 아이콘 결정 |
685
+ | Prop | Type | Required | Default | Description |
686
+ | --------------- | ----------------------------- | -------- | ---------- | --------------------------------------------------------------------------------------- |
687
+ | `title` | `string` | Yes | | 통계 제목 |
688
+ | `value` | `string` | Yes | | 통계 값 |
689
+ | `change` | `string` | | | 변화량 텍스트 (예: '+12.5%'). 비교 기준이 없으면 생략 — trend와 함께 있을 때만 렌더된다 |
690
+ | `trend` | `"up" \| "down" \| "neutral"` | | | 변화 방향. change와 함께 있을 때만 의미를 갖는다 |
691
+ | `polarity` | `"positive" \| "negative"` | | "positive" | 상승이 좋은 지표인지. 이탈률·에러 수처럼 반대인 지표는 negative로 색을 뒤집는다 |
692
+ | `description` | `string` | | | 값 아래 한 줄 보조 설명 (집계 대상·기간 등) |
693
+ | `hint` | `string` | | | 산출 근거 등 긴 설명. 툴팁과 aria-describedby로 노출 |
694
+ | `size` | `"sm" \| "md"` | | "md" | 밀도 프리셋. 요약 행에는 sm |
695
+ | `loading` | `boolean` | | false | 값 로딩 중 스켈레톤 표시 |
696
+ | `href` | `string` | | | 드릴다운 링크. 지정 시 카드가 앵커로 렌더된다 |
697
+ | `onSelect` | `() => void` | | | 드릴다운 핸들러. 지정 시 카드가 버튼으로 렌더된다 |
698
+ | `selected` | `boolean` | | false | 선택 가능한 카드 행에서 현재 선택 상태 |
699
+ | `sparklineData` | `number[]` | | | 값 옆에 그릴 미니 추세선 데이터 |
679
700
 
680
701
  #### CompositeZone
681
702
 
@@ -1539,15 +1560,16 @@ const store = useFormStore({ defaultValues: { name: "" } });
1539
1560
 
1540
1561
  **Import:** `import { Switch } from "@reopt-ai/opt-ui"`
1541
1562
 
1542
- | Prop | Type | Required | Default | Description |
1543
- | ---------------- | ---------------------------- | -------- | ------- | --------------------------- |
1544
- | `label` | `string` | | | 스위치 레이블 |
1545
- | `description` | `string` | | | 레이블 아래 설명 텍스트 |
1546
- | `checked` | `boolean` | | | 제어 모드: 체크 상태 |
1547
- | `defaultChecked` | `boolean` | | | 비제어 모드: 초기 체크 상태 |
1548
- | `onChange` | `(checked: boolean) => void` | | | 상태 변경 핸들러 |
1549
- | `size` | `"sm" \| "md" \| "lg"` | | "md" | 스위치 크기 |
1550
- | `disabled` | `boolean` | | | 비활성화 상태 |
1563
+ | Prop | Type | Required | Default | Description |
1564
+ | ---------------- | ---------------------------- | -------- | ------- | -------------------------------------------------------------------------- |
1565
+ | `label` | `string` | | | 스위치 레이블 |
1566
+ | `hint` | `string` | | | 레이블 아래 보조 설명 텍스트 |
1567
+ | `description` | `string` | | | 레이블 아래 설명 텍스트 **⚠️ deprecated since 1.9.0 — use `hint` instead** |
1568
+ | `checked` | `boolean` | | | 제어 모드: 체크 상태 |
1569
+ | `defaultChecked` | `boolean` | | | 비제어 모드: 초기 체크 상태 |
1570
+ | `onChange` | `(checked: boolean) => void` | | | 상태 변경 핸들러 |
1571
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 스위치 크기 |
1572
+ | `disabled` | `boolean` | | | 비활성화 상태 |
1551
1573
 
1552
1574
  #### Skeleton
1553
1575
 
@@ -1676,12 +1698,48 @@ const store = useFormStore({ defaultValues: { name: "" } });
1676
1698
 
1677
1699
  **Import:** `import { EmptyState } from "@reopt-ai/opt-ui"`
1678
1700
 
1679
- | Prop | Type | Required | Default | Description |
1680
- | ------------- | -------------------- | -------- | ------- | -------------------------------------------- |
1681
- | `title` | `string` | Yes | | 빈 상태 제목 |
1682
- | `description` | `string` | | | 빈 상태 설명 |
1683
- | `icon` | `ReactNode` | | | 표시할 아이콘 |
1684
- | `actions` | `EmptyStateAction[]` | | | 액션 버튼 배열. { label, onClick, variant? } |
1701
+ | Prop | Type | Required | Default | Description |
1702
+ | -------------- | ----------------------------------- | -------- | ---------- | ------------------------------------------------------------------------------ |
1703
+ | `title` | `string` | Yes | | 빈 상태 제목 |
1704
+ | `description` | `string` | | | 빈 상태 설명 |
1705
+ | `icon` | `ReactNode` | | | 표시할 아이콘 |
1706
+ | `actions` | `EmptyStateAction[] \| ReactNode` | | | 액션 버튼 배열 { label, onClick, variant? } 또는 직접 렌더할 노드 |
1707
+ | `body` | `ReactNode` | | | description 대신 넣는 리치 본문 (문단·목록·코드 스니펫) |
1708
+ | `footer` | `ReactNode` | | | 구분선 아래 보조 콘텐츠. 문서 링크·단축키 안내 등 |
1709
+ | `layout` | `"vertical" \| "horizontal"` | | "vertical" | horizontal은 아이콘을 텍스트 옆으로 옮긴다 (전체 페이지용) |
1710
+ | `titleSize` | `"sm" \| "md" \| "lg"` | | "md" | 제목 시각 크기. headingLevel과 독립 |
1711
+ | `hasBorder` | `boolean` | | false | 테두리 있는 패널로 렌더 |
1712
+ | `tone` | `"default" \| "subdued" \| "error"` | | "default" | error는 실패를 알리고 role=alert로 렌더. subdued는 아직 데이터가 없음을 뜻한다 |
1713
+ | `iconSize` | `"sm" \| "md" \| "lg"` | | "md" | 아이콘 크기 프리셋 |
1714
+ | `headingLevel` | `"h2" \| "h3" \| "h4"` | | "h3" | 문서 구조상 제목 레벨 |
1715
+
1716
+ #### DescriptionList
1717
+
1718
+ **Import:** `import { DescriptionList } from "@reopt-ai/opt-ui"`
1719
+
1720
+ | Prop | Type | Required | Default | Description |
1721
+ | ------------ | ------------------------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
1722
+ | `items` | `DescriptionListItem[]` | Yes | | term/description 쌍 배열. { id, term, description, copyValue?, hint?, wrap? } |
1723
+ | `layout` | `"grid" \| "stack" \| "inline"` | | "grid" | grid는 각 쌍을 박스로 감싼다(필드가 많은 상세 패널). stack은 평범한 정의 목록, inline은 헤더 스트립용 한 줄 배치 |
1724
+ | `columns` | `1 \| 2 \| 3 \| 4` | | 2 | grid/stack 레이아웃의 컬럼 수 |
1725
+ | `compressed` | `boolean` | | false | 밀도 축소 |
1726
+ | `labels` | `DescriptionListLabels` | | | 복사/복사됨/빈 값 문구 |
1727
+
1728
+ #### Identity
1729
+
1730
+ **Import:** `import { Identity } from "@reopt-ai/opt-ui"`
1731
+
1732
+ | Prop | Type | Required | Default | Description |
1733
+ | ------------ | --------------------------------------------- | -------- | ------- | ------------------------------------------------------------ |
1734
+ | `name` | `string \| null` | | | 표시 이름. 없으면 secondary, 그다음 id로 폴백한다 |
1735
+ | `secondary` | `string \| null` | | | 보통 이메일. 이름이 없으면 주 라벨로 승격된다 |
1736
+ | `id` | `string` | | | 최후 폴백 라벨이자 hover 시 title |
1737
+ | `avatarSrc` | `string \| null` | | | 아바타 이미지 URL |
1738
+ | `state` | `"identified" \| "anonymous"` | | | 익명 여부. 디바이스를 사람으로 오독하지 않게 배지로 표시한다 |
1739
+ | `badge` | `ReactNode` | | | state 배지 대신 표시할 내용 (라이프사이클 단계 등) |
1740
+ | `size` | `"sm" \| "md"` | | "md" | 밀도 프리셋 |
1741
+ | `hideAvatar` | `boolean` | | false | 이미 밀도가 높은 행에서 아바타 제거 |
1742
+ | `labels` | `{ identified?: string; anonymous?: string }` | | | 식별/익명 배지 문구 |
1685
1743
 
1686
1744
  #### Card
1687
1745
 
@@ -1752,16 +1810,17 @@ import {
1752
1810
 
1753
1811
  **Checkbox:**
1754
1812
 
1755
- | Prop | Type | Required | Default | Description |
1756
- | ---------------- | ---------------------------- | -------- | ------- | ---------------------------------- |
1757
- | `label` | `string` | | | 체크박스 레이블 |
1758
- | `description` | `string` | | | 레이블 아래 설명 텍스트 |
1759
- | `checked` | `boolean` | | | 제어 모드: 체크 상태 |
1760
- | `defaultChecked` | `boolean` | | | 비제어 모드: 초기 체크 상태 |
1761
- | `onChange` | `(checked: boolean) => void` | | | 상태 변경 핸들러 |
1762
- | `size` | `"sm" \| "md" \| "lg"` | | "md" | 체크박스 크기 |
1763
- | `value` | `string` | | | CheckboxGroup 내에서 사용할 값 |
1764
- | `indeterminate` | `boolean` | | false | 불확정 상태 표시 (마이너스 아이콘) |
1813
+ | Prop | Type | Required | Default | Description |
1814
+ | ---------------- | ---------------------------- | -------- | ------- | -------------------------------------------------------------------------- |
1815
+ | `label` | `string` | | | 체크박스 레이블 |
1816
+ | `hint` | `string` | | | 레이블 아래 보조 설명 텍스트 |
1817
+ | `description` | `string` | | | 레이블 아래 설명 텍스트 **⚠️ deprecated since 1.9.0 — use `hint` instead** |
1818
+ | `checked` | `boolean` | | | 제어 모드: 체크 상태 |
1819
+ | `defaultChecked` | `boolean` | | | 비제어 모드: 초기 체크 상태 |
1820
+ | `onChange` | `(checked: boolean) => void` | | | 상태 변경 핸들러 |
1821
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 체크박스 크기 |
1822
+ | `value` | `string` | | | CheckboxGroup 내에서 사용할 |
1823
+ | `indeterminate` | `boolean` | | false | 불확정 상태 표시 (마이너스 아이콘) |
1765
1824
 
1766
1825
  **CheckboxGroup:**
1767
1826
 
@@ -1790,12 +1849,13 @@ import {
1790
1849
 
1791
1850
  **Radio:**
1792
1851
 
1793
- | Prop | Type | Required | Default | Description |
1794
- | ------------- | ---------------------- | -------- | ------- | ---------------------------------------------------------- |
1795
- | `value` | `string` | | | 라디오 값 (RadioGroup 안에서는 부모가 관리하므로 optional) |
1796
- | `label` | `string` | | | 라디오 레이블 |
1797
- | `description` | `string` | | | 레이블 아래 설명 텍스트 |
1798
- | `size` | `"sm" \| "md" \| "lg"` | | "md" | 라디오 크기 |
1852
+ | Prop | Type | Required | Default | Description |
1853
+ | ------------- | ---------------------- | -------- | ------- | -------------------------------------------------------------------------- |
1854
+ | `value` | `string` | | | 라디오 값 (RadioGroup 안에서는 부모가 관리하므로 optional) |
1855
+ | `label` | `string` | | | 라디오 레이블 |
1856
+ | `hint` | `string` | | | 레이블 아래 보조 설명 텍스트 |
1857
+ | `description` | `string` | | | 레이블 아래 설명 텍스트 **⚠️ deprecated since 1.9.0 — use `hint` instead** |
1858
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 라디오 크기 |
1799
1859
 
1800
1860
  **Keyboard Shortcuts:**
1801
1861
 
@@ -1809,21 +1869,21 @@ import {
1809
1869
 
1810
1870
  **Import:** `import { DateRangePicker } from "@reopt-ai/opt-ui"`
1811
1871
 
1812
- | Prop | Type | Required | Default | Description |
1813
- | --------------------- | ----------------------------------------------------- | -------- | ------------------- | ------------------------------------------------------ |
1814
- | `value` | `DateRange` | | | 제어 모드: { start: Date \| null, end: Date \| null } |
1815
- | `onChange` | `(range: DateRange) => void` | | | 범위 변경 핸들러 |
1816
- | `presets` | `DateRangePreset[]` | | | 빠른 선택 프리셋 배열 (기본: Today, Last 7/30/90 days) |
1817
- | `placeholder` | `string` | | "Select date range" | 미선택 시 표시 텍스트 |
1818
- | `label` | `string` | | | 입력 필드 레이블 |
1819
- | `disabled` | `boolean` | | false | 비활성화 상태 |
1820
- | `format` | `(date: Date) => string` | | | 날짜 포맷 함수 |
1821
- | `comparison` | `boolean` | | false | 비교 모드 활성화 |
1822
- | `comparisonMode` | `"previous" \| "year-over-year"` | | "previous" | 비교 기준 (이전 기간 / 전년 동기) |
1823
- | `onComparisonChange` | `(comparison: boolean, mode: ComparisonMode) => void` | | | 비교 모드 변경 콜백 |
1824
- | `showGranularity` | `boolean` | | false | 시간 단위 선택기 표시 |
1825
- | `granularity` | `"hour" \| "day" \| "week" \| "month"` | | "day" | 시간 단위 |
1826
- | `onGranularityChange` | `(granularity: DateGranularity) => void` | | | 시간 단위 변경 콜백 |
1872
+ | Prop | Type | Required | Default | Description |
1873
+ | --------------------- | ---------------------------------------- | -------- | ------------------- | ------------------------------------------------------ |
1874
+ | `value` | `DateRange` | | | 제어 모드: { start: Date \| null, end: Date \| null } |
1875
+ | `onChange` | `(range: DateRange) => void` | | | 범위 변경 핸들러 |
1876
+ | `presets` | `DateRangePreset[]` | | | 빠른 선택 프리셋 배열 (기본: Today, Last 7/30/90 days) |
1877
+ | `placeholder` | `string` | | "Select date range" | 미선택 시 표시 텍스트 |
1878
+ | `label` | `string` | | | 입력 필드 레이블 |
1879
+ | `disabled` | `boolean` | | false | 비활성화 상태 |
1880
+ | `format` | `(date: Date) => string` | | | 날짜 포맷 함수 |
1881
+ | `comparison` | `boolean` | | false | 비교 모드 활성화 |
1882
+ | `comparisonMode` | `"previous" \| "year-over-year"` | | "previous" | 비교 기준 (이전 기간 / 전년 동기) |
1883
+ | `onComparisonChange` | `(mode: ComparisonMode \| null) => void` | | | 비교 모드 변경 콜백 |
1884
+ | `showGranularity` | `boolean` | | false | 시간 단위 선택기 표시 |
1885
+ | `granularity` | `"hour" \| "day" \| "week" \| "month"` | | "day" | 시간 단위 |
1886
+ | `onGranularityChange` | `(granularity: DateGranularity) => void` | | | 시간 단위 변경 콜백 |
1827
1887
 
1828
1888
  #### TagInput
1829
1889
 
@@ -2040,16 +2100,16 @@ import {
2040
2100
 
2041
2101
  **ResizablePanelGroup:**
2042
2102
 
2043
- | Prop | Type | Required | Default | Description |
2044
- | ----------------- | ------------------------------------------ | -------- | ------- | --------------------------------------------------- |
2045
- | `direction` | `"horizontal" \| "vertical"` | Yes | | 패널 분할 방향 |
2046
- | `children` | `ReactNode` | Yes | | ResizablePanel + ResizableHandle 조합 |
2047
- | `id` | `string` | | | 그룹과 defaultLayout의 패널 크기를 식별하는 고유 ID |
2048
- | `defaultLayout` | `Record<string, number>` | | | 패널 ID별 초기 비율(0-100) |
2049
- | `onLayoutChanged` | `(layout: Record<string, number>) => void` | | | 드래그가 끝난 뒤 확정된 레이아웃 콜백 |
2050
- | `groupRef` | `Ref<ResizablePanelGroupHandle>` | | | 레이아웃 조회·설정을 위한 명령형 그룹 ref |
2051
- | `autoSaveId` | `string` | | | id의 deprecated 별칭 |
2052
- | `className` | `string` | | | 커스텀 CSS 클래스 |
2103
+ | Prop | Type | Required | Default | Description |
2104
+ | ----------------- | ------------------------------------------ | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------- |
2105
+ | `direction` | `"horizontal" \| "vertical"` | Yes | | 패널 분할 방향 |
2106
+ | `children` | `ReactNode` | Yes | | ResizablePanel + ResizableHandle 조합 |
2107
+ | `id` | `string` | | | 그룹과 defaultLayout의 패널 크기를 식별하는 고유 ID |
2108
+ | `defaultLayout` | `Record<string, number>` | | | 패널 ID별 초기 비율(0-100) |
2109
+ | `onLayoutChanged` | `(layout: Record<string, number>) => void` | | | 드래그가 끝난 뒤 확정된 레이아웃 콜백 |
2110
+ | `groupRef` | `Ref<ResizablePanelGroupHandle>` | | | 레이아웃 조회·설정을 위한 명령형 그룹 ref |
2111
+ | `autoSaveId` | `string` | | | id의 deprecated 별칭 **⚠️ deprecated since 1.6.0 — use `id` instead — id + defaultLayout + onLayoutChanged 조합으로 대체되었습니다.** |
2112
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
2053
2113
 
2054
2114
  **ResizablePanel:**
2055
2115
 
@@ -2306,6 +2366,57 @@ const MyDashboard = createBlock<MyDashboardProps>(
2306
2366
  | `paused` | `boolean` | | | true면 단일 프레임만 렌더 (카드 배경 등) |
2307
2367
  | `dpr` | `number` | | | device pixel ratio 상한 (기본 min(dpr, 2)) |
2308
2368
 
2369
+ #### Callout
2370
+
2371
+ **Import:** `import { Callout } from "@reopt-ai/opt-ui"`
2372
+
2373
+ | Prop | Type | Required | Default | Description |
2374
+ | ---------- | ----------------------------------------------------------- | -------- | ------- | ------------------------------------------- |
2375
+ | `tone` | `"info" \| "success" \| "warning" \| "danger" \| "neutral"` | | "info" | 고지의 성격 |
2376
+ | `title` | `ReactNode` | | | 한 줄 제목 |
2377
+ | `icon` | `ReactNode` | | | tone 기본 글리프 대체. null이면 글리프 없음 |
2378
+ | `action` | `ReactNode` | | | 다음 한 걸음. 둘 이상이면 고지가 아니라 폼 |
2379
+ | `size` | `"sm" \| "md"` | | "md" | 밀도 |
2380
+ | `children` | `ReactNode` | | | 본문 |
2381
+
2382
+ #### StatusDot
2383
+
2384
+ **Import:** `import { StatusDot } from "@reopt-ai/opt-ui"`
2385
+
2386
+ | Prop | Type | Required | Default | Description |
2387
+ | ---------- | ---------------------------------------------------------------------- | -------- | --------- | -------------------------------------- |
2388
+ | `tone` | `"neutral" \| "muted" \| "info" \| "success" \| "warning" \| "danger"` | | "neutral" | 점 색상 |
2389
+ | `size` | `"sm" \| "md"` | | "md" | 점과 글자 크기 |
2390
+ | `children` | `ReactNode` | Yes | | 상태 라벨. 필수 — 색은 상태가 아닙니다 |
2391
+ | `hint` | `string` | | | 판정 기준 툴팁 |
2392
+
2393
+ #### CopyButton
2394
+
2395
+ **Import:** `import { CopyButton } from "@reopt-ai/opt-ui"`
2396
+
2397
+ | Prop | Type | Required | Default | Description |
2398
+ | ------------------ | ----------------------- | -------- | ------- | ------------------------------------------------------- |
2399
+ | `value` | `string` | Yes | | 복사할 텍스트 |
2400
+ | `variant` | `"icon" \| "text"` | | "icon" | 글리프만 / 글리프 + 라벨 |
2401
+ | `size` | `"sm" \| "md"` | | "md" | 버튼 크기 |
2402
+ | `feedbackDuration` | `number` | | 1500 | 확인 상태 유지 시간 (ms) |
2403
+ | `onCopy` | `(ok: boolean) => void` | | | 실제로 복사됐는지 — 비보안 컨텍스트·권한 거부에서 false |
2404
+ | `labels` | `CopyButtonLabels` | | | copy / copied / failed 문구 |
2405
+
2406
+ #### SegmentedControl
2407
+
2408
+ **Import:** `import { SegmentedControl } from "@reopt-ai/opt-ui"`
2409
+
2410
+ | Prop | Type | Required | Default | Description |
2411
+ | ------------ | ----------------------------- | -------- | ------- | ------------------------------------------------------- |
2412
+ | `options` | `SegmentedControlOption<T>[]` | Yes | | 세그먼트 목록 (value / label / icon / badge / disabled) |
2413
+ | `value` | `T` | Yes | | 선택된 값 |
2414
+ | `onChange` | `(value: T) => void` | Yes | | 선택 변경 |
2415
+ | `size` | `"sm" \| "md"` | | "md" | 컨트롤 크기 |
2416
+ | `fullWidth` | `boolean` | | false | 컨테이너를 균등 분할 |
2417
+ | `disabled` | `boolean` | | false | 전체 비활성 |
2418
+ | `aria-label` | `string` | Yes | | radiogroup 이름. 필수 |
2419
+
2309
2420
  ### Visual Layer
2310
2421
 
2311
2422
  ### Shell Layer
@@ -2319,6 +2430,13 @@ const MyDashboard = createBlock<MyDashboardProps>(
2319
2430
  | ------- | ----------- | -------- | ------- | --------------------------------------- |
2320
2431
  | `items` | `FaqItem[]` | Yes | | FAQ 항목 배열. { id, question, answer } |
2321
2432
 
2433
+ **Keyboard Shortcuts:**
2434
+
2435
+ | Keys | Action |
2436
+ | --------------- | --------------------- |
2437
+ | `↑ ↓` | 질문 사이 포커스 이동 |
2438
+ | `Enter / Space` | 답변 펼치기 또는 접기 |
2439
+
2322
2440
  #### PageAside
2323
2441
 
2324
2442
  **Import:** `import { PageAside } from "@reopt-ai/opt-ui"`
@@ -2455,33 +2573,42 @@ const fields = [
2455
2573
  | ------- | ----------- | -------- | ------- | --------------------------------------------------- |
2456
2574
  | `menus` | `MenuDef[]` | Yes | | 메뉴 정의 배열. { id, label, items: MenuItemDef[] } |
2457
2575
 
2576
+ **Keyboard Shortcuts:**
2577
+
2578
+ | Keys | Action |
2579
+ | ------------------- | -------------------------- |
2580
+ | `← →` | 상위 메뉴 사이 포커스 이동 |
2581
+ | `Enter / Space / ↓` | 메뉴 열기 |
2582
+ | `↑ ↓` | 열린 메뉴 항목 이동 |
2583
+ | `Escape` | 메뉴 닫고 트리거로 복귀 |
2584
+
2458
2585
  #### CommandPalette
2459
2586
 
2460
2587
  **Import:** `import { CommandPalette } from "@reopt-ai/opt-ui"`
2461
2588
  **Dependencies:** dialog (core), combobox (core), kbd (core)
2462
2589
 
2463
- | Prop | Type | Required | Default | Description |
2464
- | --------------- | -------------------------------------------- | -------- | ------- | ----------------------------------------------------- |
2465
- | `commands` | `Omit<Command, "action">[]` | Yes | | 커맨드 목록. { id, label, group, shortcut? } |
2466
- | `open` | `boolean` | Yes | | 열림 상태 |
2467
- | `onOpenChange` | `(open: boolean) => void` | Yes | | 상태 변경 핸들러 |
2468
- | `onSelect` | `(command: Omit<Command, 'action'>) => void` | | | 커맨드 선택 핸들러 |
2469
- | `inline` | `boolean` | | false | true일 때 풀스크린 Dialog 대신 인라인 팝업으로 렌더링 |
2470
- | `labels` | `CommandPaletteLabels` | | | title/description/input/list/empty/escape 문구 |
2471
- | `footer` | `ReactNode` | | | 명령 목록 아래에 표시할 footer slot |
2472
- | `empty` | `ReactNode` | | | 결과가 없을 때 표시할 empty slot |
2473
- | `inputTrailing` | `ReactNode` | | | 검색 입력 우측 보조 콘텐츠 |
2590
+ | Prop | Type | Required | Default | Description |
2591
+ | --------------- | ----------------------------------------------- | -------- | ------- | ----------------------------------------------------- |
2592
+ | `commands` | `Omit<CommandDef, "action">[]` | Yes | | 커맨드 목록. { id, label, group, shortcut? } |
2593
+ | `open` | `boolean` | Yes | | 열림 상태 |
2594
+ | `onOpenChange` | `(open: boolean) => void` | Yes | | 상태 변경 핸들러 |
2595
+ | `onSelect` | `(command: Omit<CommandDef, "action">) => void` | | | 커맨드 선택 핸들러 |
2596
+ | `inline` | `boolean` | | false | true일 때 풀스크린 Dialog 대신 인라인 팝업으로 렌더링 |
2597
+ | `labels` | `CommandPaletteLabels` | | | title/description/input/list/empty/escape 문구 |
2598
+ | `footer` | `ReactNode` | | | 명령 목록 아래에 표시할 footer slot |
2599
+ | `empty` | `ReactNode` | | | 결과가 없을 때 표시할 empty slot |
2600
+ | `inputTrailing` | `ReactNode` | | | 검색 입력 우측 보조 콘텐츠 |
2474
2601
 
2475
2602
  #### CommandPaletteTrigger
2476
2603
 
2477
2604
  **Import:** `import { CommandPaletteTrigger } from "@reopt-ai/opt-ui"`
2478
2605
  **Dependencies:** command-palette (shells)
2479
2606
 
2480
- | Prop | Type | Required | Default | Description |
2481
- | ---------- | -------------------------------------------- | -------- | ------- | -------------------------------------------------- |
2482
- | `commands` | `Omit<Command, "action">[]` | Yes | | 커맨드 목록 |
2483
- | `onSelect` | `(command: Omit<Command, 'action'>) => void` | | | 커맨드 선택 핸들러 |
2484
- | `labels` | `CommandPaletteTriggerLabels` | | | 내부 CommandPalette에 전달할 title/input/list 문구 |
2607
+ | Prop | Type | Required | Default | Description |
2608
+ | ---------- | ----------------------------------------------- | -------- | ------- | -------------------------------------------------- |
2609
+ | `commands` | `Omit<CommandDef, "action">[]` | Yes | | 커맨드 목록 |
2610
+ | `onSelect` | `(command: Omit<CommandDef, "action">) => void` | | | 커맨드 선택 핸들러 |
2611
+ | `labels` | `CommandPaletteTriggerLabels` | | | 내부 CommandPalette에 전달할 title/input/list 문구 |
2485
2612
 
2486
2613
  #### DeploymentTimeline
2487
2614
 
@@ -2691,11 +2818,11 @@ import { DataTable } from "@reopt-ai/opt-ui";
2691
2818
  **Import:** `import { FilterBar } from "@reopt-ai/opt-ui"`
2692
2819
  **Dependencies:** select (core), input (core), button (core), switch (core), checkbox (core), date-range-picker (core)
2693
2820
 
2694
- | Prop | Type | Required | Default | Description |
2695
- | ---------------- | ------------------------------------------------------- | -------- | ------- | ----------------------------------------------------- |
2696
- | `filters` | `FilterGroupDef[]` | Yes | | 필터 그룹 배열. { id, label, type, options?, value? } |
2697
- | `onFilterChange` | `(filterId: string, value: string \| string[]) => void` | | | 필터 변경 핸들러 |
2698
- | `onClearAll` | `() => void` | | | 모든 필터 초기화 핸들러 |
2821
+ | Prop | Type | Required | Default | Description |
2822
+ | ---------------- | ------------------------------------------------------------------ | -------- | ------- | ----------------------------------------------------- |
2823
+ | `filters` | `FilterGroupDef[]` | Yes | | 필터 그룹 배열. { id, label, type, options?, value? } |
2824
+ | `onFilterChange` | `(filterId: string, value: string \| string[] \| boolean) => void` | | | 필터 변경 핸들러 |
2825
+ | `onClearAll` | `() => void` | | | 모든 필터 초기화 핸들러 |
2699
2826
 
2700
2827
  **Examples:**
2701
2828
 
@@ -2761,15 +2888,15 @@ const filters = [
2761
2888
  **Import:** `import { AuthForm } from "@reopt-ai/opt-ui"`
2762
2889
  **Dependencies:** form (core)
2763
2890
 
2764
- | Prop | Type | Required | Default | Description |
2765
- | ------------------- | ---------------------------------------------------------------------------- | -------- | ------- | -------------------------------------------- |
2766
- | `defaultMode` | `"login" \| "signup"` | | "login" | 초기 모드 (비제어) |
2767
- | `mode` | `"login" \| "signup"` | | | 제어 모드: 현재 모드 |
2768
- | `onModeChange` | `(mode: "login" \| "signup") => void` | | | 모드 변경 핸들러 |
2769
- | `showRememberMe` | `boolean` | | true | 로그인 모드에서 '로그인 상태 유지' 표시 여부 |
2770
- | `minPasswordLength` | `number` | | 8 | 비밀번호 최소 길이 |
2771
- | `onSubmit` | `(values: { email, password, confirmPassword?, rememberMe?, mode }) => void` | | | 제출 핸들러 |
2772
- | `labels` | `AuthFormLabels` | | | i18n용 라벨 오버라이드 |
2891
+ | Prop | Type | Required | Default | Description |
2892
+ | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------- | ------- | -------------------------------------------- |
2893
+ | `defaultMode` | `"login" \| "signup"` | | "login" | 초기 모드 (비제어) |
2894
+ | `mode` | `"login" \| "signup"` | | | 제어 모드: 현재 모드 |
2895
+ | `onModeChange` | `(mode: "login" \| "signup") => void` | | | 모드 변경 핸들러 |
2896
+ | `showRememberMe` | `boolean` | | true | 로그인 모드에서 '로그인 상태 유지' 표시 여부 |
2897
+ | `minPasswordLength` | `number` | | 8 | 비밀번호 최소 길이 |
2898
+ | `onSubmit` | `(values: { email: string; password: string; confirmPassword?: string; rememberMe?: boolean; mode: "login" \| "signup" }) => void` | | | 제출 핸들러 |
2899
+ | `labels` | `AuthFormLabels` | | | i18n용 라벨 오버라이드 |
2773
2900
 
2774
2901
  #### WizardForm
2775
2902
 
@@ -2805,17 +2932,17 @@ const filters = [
2805
2932
  **Import:** `import { FileUploadForm } from "@reopt-ai/opt-ui"`
2806
2933
  **Dependencies:** form (core)
2807
2934
 
2808
- | Prop | Type | Required | Default | Description |
2809
- | ----------------- | ------------------------------------------------ | -------- | ------------------------- | ----------------------------------------- |
2810
- | `accept` | `string` | | "image/*,.pdf,.doc,.docx" | 허용 파일 타입 |
2811
- | `showPreview` | `boolean` | | true | 이미지 미리보기 표시 |
2812
- | `showFileInfo` | `boolean` | | true | 파일 정보 표시 |
2813
- | `showDescription` | `boolean` | | true | 설명 텍스트영역 표시 |
2814
- | `maxFileSize` | `number` | | | 최대 파일 크기 (bytes) |
2815
- | `onSubmit` | `(values: { title, description, file }) => void` | | | 제출 핸들러 |
2816
- | `labels` | `FileUploadFormLabels` | | | i18n용 라벨 오버라이드 |
2817
- | `onPreview` | `(file: File) => void` | | | 파일 선택 후 프리뷰 콜백 |
2818
- | `columnMapping` | `ReactNode` | | | CSV 컬럼 매핑 UI 슬롯 (파일 선택 후 표시) |
2935
+ | Prop | Type | Required | Default | Description |
2936
+ | ----------------- | ------------------------------------------------------------------------------ | -------- | ------------------------- | ----------------------------------------- |
2937
+ | `accept` | `string` | | "image/*,.pdf,.doc,.docx" | 허용 파일 타입 |
2938
+ | `showPreview` | `boolean` | | true | 이미지 미리보기 표시 |
2939
+ | `showFileInfo` | `boolean` | | true | 파일 정보 표시 |
2940
+ | `showDescription` | `boolean` | | true | 설명 텍스트영역 표시 |
2941
+ | `maxFileSize` | `number` | | | 최대 파일 크기 (bytes) |
2942
+ | `onSubmit` | `(values: { title: string; description: string; file: File \| null }) => void` | | | 제출 핸들러 |
2943
+ | `labels` | `FileUploadFormLabels` | | | i18n용 라벨 오버라이드 |
2944
+ | `onPreview` | `(file: File) => void` | | | 파일 선택 후 프리뷰 콜백 |
2945
+ | `columnMapping` | `ReactNode` | | | CSV 컬럼 매핑 UI 슬롯 (파일 선택 후 표시) |
2819
2946
 
2820
2947
  #### EventIcon
2821
2948
 
@@ -2970,16 +3097,16 @@ const filters = [
2970
3097
  **Import:** `import { ReportBuilder } from "@reopt-ai/opt-ui"`
2971
3098
  **Dependencies:** button (core), input (core)
2972
3099
 
2973
- | Prop | Type | Required | Default | Description |
2974
- | ------------- | ------------------------------------------------------------------ | -------- | ------- | ----------------------------------- |
2975
- | `chartTypes` | `ChartTypeDef[]` | | | 차트 타입 그리드 (기본 9종 제공) |
2976
- | `dataSources` | `DataSourceDef[]` | | | 데이터 소스 드롭다운 옵션 |
2977
- | `configForm` | `ReactNode` | | | 차트별 데이터 설정 폼 슬롯 (step 2) |
2978
- | `styleForm` | `ReactNode` | | | 차트별 스타일 설정 폼 슬롯 (step 3) |
2979
- | `preview` | `ReactNode` | | | 차트 미리보기 슬롯 (step 4) |
2980
- | `onSave` | `(report: { name, description, chartType, dataSourceId }) => void` | | | 저장 콜백 |
2981
- | `onCancel` | `() => void` | | | 취소 콜백 |
2982
- | `labels` | `ReportBuilderLabels` | | | UI 텍스트 커스터마이징 |
3100
+ | Prop | Type | Required | Default | Description |
3101
+ | ------------- | ------------------------------------------------------------------------------------------------------------------ | -------- | ------- | ----------------------------------- |
3102
+ | `chartTypes` | `ChartTypeDef[]` | | | 차트 타입 그리드 (기본 9종 제공) |
3103
+ | `dataSources` | `DataSourceDef[]` | | | 데이터 소스 드롭다운 옵션 |
3104
+ | `configForm` | `ReactNode` | | | 차트별 데이터 설정 폼 슬롯 (step 2) |
3105
+ | `styleForm` | `ReactNode` | | | 차트별 스타일 설정 폼 슬롯 (step 3) |
3106
+ | `preview` | `ReactNode` | | | 차트 미리보기 슬롯 (step 4) |
3107
+ | `onSave` | `(report: { name: string; description: string; chartType: ReportBuilderChartType; dataSourceId: string }) => void` | | | 저장 콜백 |
3108
+ | `onCancel` | `() => void` | | | 취소 콜백 |
3109
+ | `labels` | `ReportBuilderLabels` | | | UI 텍스트 커스터마이징 |
2983
3110
 
2984
3111
  #### InsightsPanel
2985
3112
 
@@ -3025,15 +3152,76 @@ const filters = [
3025
3152
  **Import:** `import { SummaryRow } from "@reopt-ai/opt-ui"`
3026
3153
  **Dependencies:** stat-card (core), skeleton (core)
3027
3154
 
3028
- | Prop | Type | Required | Default | Description |
3029
- | -------------------------- | -------------------------------- | -------- | ------- | -------------------------------- |
3030
- | `stats` | `StatCardType[]` | Yes | | 통계 카드 배열 |
3031
- | `columns` | `2 \| 3 \| 4` | | 4 | 컬럼 수 |
3032
- | `onStatClick` | `(stat: StatCardType) => void` | | | 카드 클릭 핸들러 |
3033
- | `formatValue` | `(stat: StatCardType) => string` | | | 표시 커스텀 포맷 함수 |
3034
- | `durationFractionDigits` | `number` | | 1 | duration 포맷 소수점 자리수 |
3035
- | `percentageFractionDigits` | `number` | | 1 | percentage 포맷 소수점 자리수 |
3036
- | `loading` | `boolean` | | false | 로딩스켈레톤 표시 |
3155
+ | Prop | Type | Required | Default | Description |
3156
+ | -------------------------- | -------------------------------- | -------- | ------- | ------------------------------------------------------- |
3157
+ | `stats` | `StatCardType[]` | Yes | | 통계 카드 배열 |
3158
+ | `columns` | `2 \| 3 \| 4 \| 5 \| 6` | | 4 | 컬럼 수 |
3159
+ | `onStatClick` | `(stat: StatCardType) => void` | | | 카드 클릭 핸들러. 지정 시 카드 자체가 버튼으로 렌더된다 |
3160
+ | `selectedStatId` | `string` | | | 선택 가능한 행에서 현재 뷰를 이끄는 카드 id |
3161
+ | `size` | `"sm" \| "md"` | | "md" | 카드 밀도. 헤더 스트립에는 sm |
3162
+ | `formatValue` | `(stat: StatCardType) => string` | | | 표시 커스텀 포맷 함수 |
3163
+ | `durationFractionDigits` | `number` | | 1 | duration 포맷 소수점 자리수 |
3164
+ | `percentageFractionDigits` | `number` | | 1 | percentage 포맷 시 소수점 자리수 |
3165
+ | `loading` | `boolean` | | false | 로딩 시 스켈레톤 표시 |
3166
+
3167
+ #### EventTimeline
3168
+
3169
+ **Import:** `import { EventTimeline } from "@reopt-ai/opt-ui"`
3170
+
3171
+ | Prop | Type | Required | Default | Description |
3172
+ | -------------- | ----------------------------------- | -------- | ------- | ----------------------------------------------------------------------------- |
3173
+ | `items` | `EventTimelineItem[]` | | | 평면 목록. groups가 있으면 무시된다 |
3174
+ | `groups` | `EventTimelineGroup[]` | | | 그룹(주로 세션) 단위 목록. 접기/펼치기와 그룹 요약을 제공 |
3175
+ | `showGaps` | `boolean` | | true | 인접 이벤트 사이 경과 시간 표시. 체크아웃 직전 4분 정지 같은 것이 발견이 된다 |
3176
+ | `order` | `"desc" \| "asc"` | | "desc" | 전달된 items의 정렬 방향. 경과 시간 계산 기준 |
3177
+ | `minGapMs` | `number` | | 1000 | 이 값 미만의 간격은 라벨을 생략 |
3178
+ | `loading` | `boolean` | | false | 스켈레톤 표시 |
3179
+ | `hasMore` | `boolean` | | false | 더 불러올 항목 존재 |
3180
+ | `onLoadMore` | `() => void` | | | 더 보기 핸들러 |
3181
+ | `onItemSelect` | `(item: EventTimelineItem) => void` | | | 이벤트 헤드라인 클릭 핸들러 |
3182
+ | `locale` | `string` | | | 경과 시간 포맷 로케일 |
3183
+ | `labels` | `EventTimelineLabels` | | | 문구 오버라이드 |
3184
+
3185
+ #### ScoreBreakdown
3186
+
3187
+ **Import:** `import { ScoreBreakdown } from "@reopt-ai/opt-ui"`
3188
+
3189
+ | Prop | Type | Required | Default | Description |
3190
+ | --------- | ---------------------- | -------- | ------- | -------------------------------------------------- |
3191
+ | `score` | `number` | Yes | | 총점 |
3192
+ | `max` | `number` | | 100 | 총점 상한 |
3193
+ | `axes` | `ScoreAxis[]` | Yes | | 기여 축 배열. { id, label, value, hint?, weight? } |
3194
+ | `bands` | `ScoreBand[]` | | | 점수 구간 이름과 색. { min, label, tone? } |
3195
+ | `formula` | `ReactNode` | | | 총점 산출식 설명 한 줄 |
3196
+ | `loading` | `boolean` | | false | 스켈레톤 표시 |
3197
+ | `labels` | `ScoreBreakdownLabels` | | | 문구 오버라이드 |
3198
+
3199
+ #### Flyout
3200
+
3201
+ **Import:** `import { Flyout } from "@reopt-ai/opt-ui"`
3202
+
3203
+ | Prop | Type | Required | Default | Description |
3204
+ | --------------------- | ----------------------- | -------- | --------- | ----------------------------------------------------------------------------------- |
3205
+ | `open` | `boolean` | Yes | | 열림 상태 |
3206
+ | `onClose` | `() => void` | Yes | | 닫기 핸들러 |
3207
+ | `title` | `ReactNode` | | | 패널 제목 |
3208
+ | `description` | `ReactNode` | | | 제목 아래 한 줄 설명 |
3209
+ | `type` | `"overlay" \| "inline"` | | "overlay" | overlay는 페이지 위에 띄우고, inline은 aside로 렌더해 배치를 부모 레이아웃에 맡긴다 |
3210
+ | `side` | `"right" \| "left"` | | "right" | overlay일 때 붙는 방향 |
3211
+ | `size` | `"sm" \| "md" \| "lg"` | | "md" | 패널 너비 |
3212
+ | `actions` | `ReactNode` | | | 닫기 버튼 앞 컨트롤 |
3213
+ | `footer` | `ReactNode` | | | 하단 고정 영역 |
3214
+ | `scrim` | `boolean` | | false | 뒤 페이지를 어둡게. 기본 off — 목록이 계속 읽혀야 한다 |
3215
+ | `closeOnOutsideClick` | `boolean` | | true | 바깥 클릭 시 닫기 (overlay 전용) |
3216
+ | `hideCloseButton` | `boolean` | | false | 닫기 버튼 숨김 |
3217
+ | `labels` | `FlyoutLabels` | | | 문구 오버라이드 |
3218
+ | `children` | `ReactNode` | Yes | | 패널 본문 |
3219
+
3220
+ **Keyboard Shortcuts:**
3221
+
3222
+ | Keys | Action |
3223
+ | -------- | ----------------------------------- |
3224
+ | `Escape` | 패널 닫고 여는 컨트롤로 포커스 복귀 |
3037
3225
 
3038
3226
  #### ComparisonSelector
3039
3227
 
@@ -3164,15 +3352,15 @@ import { AppShell } from "@reopt-ai/opt-ui";
3164
3352
  **Import:** `import { AsyncCombobox } from "@reopt-ai/opt-ui"`
3165
3353
  **Dependencies:** combobox (core), spinner (core)
3166
3354
 
3167
- | Prop | Type | Required | Default | Description |
3168
- | ------------- | ---------------------------------- | -------- | --------- | ---------------------------------------- |
3169
- | `onSearch` | `(q: string) => Promise<string[]>` | Yes | | 검색 콜백 |
3170
- | `debounceMs` | `number` | | 300 | 디바운스 ms |
3171
- | `minChars` | `number` | | 1 | 최소 검색 글자 수 |
3172
- | `placeholder` | `string` | | "Search…" | 플레이스홀더 |
3173
- | `onSelect` | `(value: string) => void` | | | 선택 콜백 |
3174
- | `labels` | `AsyncComboboxLabels` | | | input/loading/noResults/placeholder 문구 |
3175
- | `loadingText` | `string` | | | 로딩 문구. labels.loading 사용 권장 |
3355
+ | Prop | Type | Required | Default | Description |
3356
+ | ------------- | -------------------------------------- | -------- | --------- | ----------------------------------------------------------------------------- |
3357
+ | `onSearch` | `(query: string) => Promise<string[]>` | Yes | | 검색 콜백 |
3358
+ | `debounceMs` | `number` | | 300 | 디바운스 ms |
3359
+ | `minChars` | `number` | | 1 | 최소 검색 글자 수 |
3360
+ | `placeholder` | `string` | | "Search…" | 플레이스홀더 **⚠️ deprecated since 1.9.0 — use `labels.placeholder` instead** |
3361
+ | `onSelect` | `(value: string) => void` | | | 선택 콜백 |
3362
+ | `labels` | `AsyncComboboxLabels` | | | input/loading/noResults/placeholder 문구 |
3363
+ | `loadingText` | `string` | | | 로딩 문구 **⚠️ deprecated since 1.9.0 — use `labels.loading` instead** |
3176
3364
 
3177
3365
  #### VerticalTabs
3178
3366
 
@@ -3185,6 +3373,13 @@ import { AppShell } from "@reopt-ai/opt-ui";
3185
3373
  | `defaultTabId` | `string` | | | 기본 선택 탭 ID |
3186
3374
  | `className` | `string` | | | 커스텀 CSS 클래스 |
3187
3375
 
3376
+ **Keyboard Shortcuts:**
3377
+
3378
+ | Keys | Action |
3379
+ | ------------ | ------------------------------- |
3380
+ | `↑ ↓` | 세로 탭 사이 이동 및 선택 |
3381
+ | `Home / End` | 첫 번째 또는 마지막 탭으로 이동 |
3382
+
3188
3383
  #### ColumnToggler
3189
3384
 
3190
3385
  **Import:** `import { ColumnToggler } from "@reopt-ai/opt-ui"`
@@ -3201,13 +3396,22 @@ import { AppShell } from "@reopt-ai/opt-ui";
3201
3396
  **Import:** `import { TreeTable } from "@reopt-ai/opt-ui"`
3202
3397
  **Dependencies:** data-table (shells)
3203
3398
 
3204
- | Prop | Type | Required | Default | Description |
3205
- | ----------------- | -------------------- | -------- | ------- | ------------------ |
3206
- | `data` | `TreeNode<T>[]` | Yes | | 트리 노드 배열 |
3207
- | `columns` | `TreeColumnDef<T>[]` | Yes | | 컬럼 정의 |
3208
- | `defaultExpanded` | `string[]` | | [] | 기본 펼침 노드 ID |
3209
- | `indentSize` | `number` | | 24 | 들여쓰기 크기 (px) |
3210
- | `className` | `string` | | | 커스텀 CSS 클래스 |
3399
+ | Prop | Type | Required | Default | Description |
3400
+ | ----------------- | ------------------------------- | -------- | ------- | ----------------------------------------------- |
3401
+ | `data` | `TreeNode<T>[]` | Yes | | 트리 노드 배열 |
3402
+ | `columns` | `TreeColumnDef<T>[]` | Yes | | 컬럼 정의 |
3403
+ | `defaultExpanded` | `string[]` | | [] | 기본 펼침 노드 ID |
3404
+ | `indentSize` | `number` | | 24 | 들여쓰기 크기 (px) |
3405
+ | `getRowLabel` | `(node: TreeNode<T>) => string` | | | 행별 펼침/접기 컨트롤의 접근 가능한 이름 생성기 |
3406
+ | `aria-label` | `string` | | | 표의 접근 가능한 이름 |
3407
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
3408
+
3409
+ **Keyboard Shortcuts:**
3410
+
3411
+ | Keys | Action |
3412
+ | --------------- | -------------------------- |
3413
+ | `Tab` | 펼침/접기 컨트롤 사이 이동 |
3414
+ | `Enter / Space` | 하위 행 펼치기 또는 접기 |
3211
3415
 
3212
3416
  #### InlineEditTable
3213
3417
 
@@ -3227,13 +3431,13 @@ import { AppShell } from "@reopt-ai/opt-ui";
3227
3431
  **Import:** `import { KanbanBoard } from "@reopt-ai/opt-ui"`
3228
3432
  **Dependencies:** scroll-area (core)
3229
3433
 
3230
- | Prop | Type | Required | Default | Description |
3231
- | -------------- | ------------------------------------------- | -------- | ------- | -------------------------------- |
3232
- | `columns` | `KanbanColumn<T>[]` | Yes | | 컬럼 목록 (각 컬럼에 items 배열) |
3233
- | `onDragEnd` | `(itemId, fromCol, toCol, toIndex) => void` | Yes | | 드래그 완료 콜백 |
3234
- | `renderCard` | `(item: T) => ReactNode` | Yes | | 카드 렌더링 함수 |
3235
- | `keyExtractor` | `(item: T) => string` | Yes | | 항목 키 추출기 |
3236
- | `className` | `string` | | | 커스텀 CSS 클래스 |
3434
+ | Prop | Type | Required | Default | Description |
3435
+ | -------------- | ------------------------------------------------------------------------------------- | -------- | ------- | -------------------------------- |
3436
+ | `columns` | `KanbanColumn<T>[]` | Yes | | 컬럼 목록 (각 컬럼에 items 배열) |
3437
+ | `onDragEnd` | `(itemId: string, fromColumnId: string, toColumnId: string, toIndex: number) => void` | Yes | | 드래그 완료 콜백 |
3438
+ | `renderCard` | `(item: T) => ReactNode` | Yes | | 카드 렌더링 함수 |
3439
+ | `keyExtractor` | `(item: T) => string` | Yes | | 항목 키 추출기 |
3440
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
3237
3441
 
3238
3442
  #### RichTextEditor
3239
3443
 
@@ -3291,25 +3495,34 @@ import { AppShell } from "@reopt-ai/opt-ui";
3291
3495
  **Import:** `import { DataImportWizard } from "@reopt-ai/opt-ui"`
3292
3496
  **Dependencies:** button (core)
3293
3497
 
3294
- | Prop | Type | Required | Default | Description |
3295
- | ----------------- | ------------------------- | -------- | ------- | ------------------- |
3296
- | `fields` | `ImportFieldDef[]` | Yes | | 매핑 대상 필드 목록 |
3297
- | `onImport` | `(mapping, data) => void` | Yes | | 임포트 확정 콜백 |
3298
- | `acceptedFormats` | `string` | | ".csv" | 허용 파일 형식 |
3299
- | `className` | `string` | | | 커스텀 CSS 클래스 |
3498
+ | Prop | Type | Required | Default | Description |
3499
+ | ----------------- | ------------------------------------------------------------- | -------- | ------- | ------------------- |
3500
+ | `fields` | `ImportFieldDef[]` | Yes | | 매핑 대상 필드 목록 |
3501
+ | `onImport` | `(mapping: Record<string, string>, data: string[][]) => void` | Yes | | 임포트 확정 콜백 |
3502
+ | `acceptedFormats` | `string` | | ".csv" | 허용 파일 형식 |
3503
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
3300
3504
 
3301
3505
  #### MegaMenu
3302
3506
 
3303
3507
  **Import:** `import { MegaMenu } from "@reopt-ai/opt-ui"`
3304
3508
  **Dependencies:** popover (core)
3305
3509
 
3306
- | Prop | Type | Required | Default | Description |
3307
- | -------------- | ------------------- | -------- | ------- | ------------------ |
3308
- | `menus` | `MegaMenuSection[]` | Yes | | 메뉴 섹션 배열 |
3309
- | `columns` | `number` | | 3 | 그리드 컬럼 수 |
3310
- | `footer` | `ReactNode` | | | 하단 footer 슬롯 |
3311
- | `triggerLabel` | `string` | | "Menu" | 트리거 버튼 텍스트 |
3312
- | `className` | `string` | | | 커스텀 CSS 클래스 |
3510
+ | Prop | Type | Required | Default | Description |
3511
+ | -------------- | ------------------- | -------- | ------- | ------------------------------------------- |
3512
+ | `menus` | `MegaMenuSection[]` | Yes | | 메뉴 섹션 배열 |
3513
+ | `columns` | `number` | | 3 | 그리드 컬럼 수 |
3514
+ | `footer` | `ReactNode` | | | 하단 footer 슬롯 |
3515
+ | `triggerLabel` | `string` | | "Menu" | 트리거 버튼 텍스트 |
3516
+ | `aria-label` | `string` | | | 열린 메가 메뉴 탐색 영역의 접근 가능한 이름 |
3517
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
3518
+
3519
+ **Keyboard Shortcuts:**
3520
+
3521
+ | Keys | Action |
3522
+ | --------------- | -------------------------- |
3523
+ | `Enter / Space` | 메가 메뉴 열기 |
3524
+ | `Tab` | 메뉴 링크와 액션 사이 이동 |
3525
+ | `Escape` | 메가 메뉴 닫기 |
3313
3526
 
3314
3527
  #### BulkActions
3315
3528
 
@@ -3499,16 +3712,19 @@ const messages = [
3499
3712
 
3500
3713
  **Import:** `import { TimeSeriesPanel } from "@reopt-ai/opt-ui"`
3501
3714
 
3502
- | Prop | Type | Required | Default | Description |
3503
- | ------------------ | ---------------------------- | -------- | ------- | --------------------------------------------- |
3504
- | `data` | `TimeSeriesPoint[]` | Yes | | 시계열 데이터 |
3505
- | `series` | `TimeSeriesDef[]` | Yes | | 시리즈 정의 |
3506
- | `range` | `TimeRange` | Yes | | 조회 구간 — 차트 축도 여기에 고정됩니다 |
3507
- | `onRangeChange` | `(range: TimeRange) => void` | Yes | | 드래그 줌·컨트롤 변경으로 구간이 바뀔 때 호출 |
3508
- | `showRangeControl` | `boolean` | | true | 헤더에 TimeRangeControl 렌더 |
3509
- | `toggleableLegend` | `boolean` | | false | 범례 클릭으로 시리즈 숨김 |
3510
- | `annotations` | `TimeSeriesAnnotation[]` | | | 시간축 마커/구간 |
3511
- | `height` | `number` | | 280 | 차트 높이 |
3715
+ | Prop | Type | Required | Default | Description |
3716
+ | ------------------ | ---------------------------- | -------- | ------- | --------------------------------------------------------- |
3717
+ | `title` | `ReactNode` | | | 패널 제목. aria-label이 없으면 region 이름으로 연결됩니다 |
3718
+ | `description` | `ReactNode` | | | 패널 보조 설명 |
3719
+ | `data` | `TimeSeriesPoint[]` | Yes | | 시계열 데이터 |
3720
+ | `series` | `TimeSeriesDef[]` | Yes | | 시리즈 정의 |
3721
+ | `range` | `TimeRange` | Yes | | 조회 구간 — 차트 축도 여기에 고정됩니다 |
3722
+ | `onRangeChange` | `(range: TimeRange) => void` | Yes | | 드래그 줌·컨트롤 변경으로 구간이 바뀔 때 호출 |
3723
+ | `showRangeControl` | `boolean` | | true | 헤더에 TimeRangeControl 렌더 |
3724
+ | `toggleableLegend` | `boolean` | | false | 범례 클릭으로 시리즈 숨김 |
3725
+ | `annotations` | `TimeSeriesAnnotation[]` | | | 시간축 마커/구간 |
3726
+ | `height` | `number` | | 280 | 차트 높이 |
3727
+ | `aria-label` | `string` | | | 제목 대신 사용할 패널 region의 접근 가능한 이름 |
3512
3728
 
3513
3729
  #### LogTable
3514
3730
 
@@ -3558,4 +3774,92 @@ const messages = [
3558
3774
  | `onToggleColumn` | `(field: string, next: boolean) => void` | | | 컬럼 추가/제거 |
3559
3775
  | `onFilter` | `(field: string, value: string, intent: "include" \| "exclude") => void` | | | 값 기준 필터 |
3560
3776
 
3777
+ #### InspectorLayout
3778
+
3779
+ **Import:** `import { InspectorLayout } from "@reopt-ai/opt-ui"`
3780
+
3781
+ | Prop | Type | Required | Default | Description |
3782
+ | ------------- | ----------------------- | -------- | ------- | ---------------------------------------------- |
3783
+ | `children` | `ReactNode` | Yes | | 목록. 인스펙터가 열려도 마운트와 스크롤을 유지 |
3784
+ | `inspector` | `ReactNode` | | | 인스펙터 내용. 닫혀 있으면 렌더하지 않음 |
3785
+ | `open` | `boolean` | Yes | | 열림 |
3786
+ | `onClose` | `() => void` | Yes | | 닫기 |
3787
+ | `title` | `ReactNode` | | | 인스펙터 제목 |
3788
+ | `description` | `ReactNode` | | | 제목 아래 한 줄 |
3789
+ | `actions` | `ReactNode` | | | 닫기 버튼 옆 컨트롤 |
3790
+ | `footer` | `ReactNode` | | | 인스펙터 하단 |
3791
+ | `breakpoint` | `"lg" \| "xl" \| "2xl"` | | "xl" | 이 폭 이상이면 push |
3792
+ | `width` | `"sm" \| "md" \| "lg"` | | "md" | push 레이아웃에서의 인스펙터 폭 |
3793
+
3794
+ #### QueryFilterBar
3795
+
3796
+ **Import:** `import { QueryFilterBar } from "@reopt-ai/opt-ui"`
3797
+
3798
+ | Prop | Type | Required | Default | Description |
3799
+ | ---------------- | ------------------------ | -------- | ------- | -------------------------------------------------------------------------- |
3800
+ | `value` | `Query` | Yes | | 필터 상태 전부 |
3801
+ | `onChange` | `(query: Query) => void` | Yes | | Query 변경 |
3802
+ | `filters` | `QueryFilterDef[]` | Yes | | 필터 컨트롤 정의 (is / field_value_selection / field_value_toggle) |
3803
+ | `fields` | `QueryField[]` | | | 텍스트 입력 자동완성 |
3804
+ | `actions` | `ReactNode` | | | 필터 행 끝 슬롯 |
3805
+ | `showClauses` | `boolean` | | true | 절을 제거 가능한 칩으로 표시 |
3806
+ | `live` | `boolean` | | false | 매 입력마다 커밋 |
3807
+ | `disabled` | `boolean` | | false | 전체 비활성 |
3808
+ | `queryBarLabels` | `QueryBarLabels` | | | QueryBar로 통과되는 나머지 문구. placeholder/ariaLabel은 labels가 이깁니다 |
3809
+
3810
+ #### CatalogFrame
3811
+
3812
+ **Import:** `import { CatalogFrame } from "@reopt-ai/opt-ui"`
3813
+
3814
+ **CatalogFrame:**
3815
+
3816
+ | Prop | Type | Required | Default | Description |
3817
+ | ---------------------- | ------------------------------ | -------- | ------- | ----------------------------------------------------------------- |
3818
+ | `children` | `ReactNode` | Yes | | 테이블. 빈/에러 상태에서는 대체됨 |
3819
+ | `isEmpty` | `boolean` | Yes | | 테이블이 0행인지 |
3820
+ | `query` | `Query` | Yes | | 필터 상태 |
3821
+ | `onQueryChange` | `(query: Query) => void` | Yes | | Query 변경 |
3822
+ | `filters` | `QueryFilterDef[]` | | | 필터 정의 |
3823
+ | `stats` | `StatCardType[]` | | | 통계 카드 |
3824
+ | `onStatClick` | `(stat: StatCardType) => void` | | | 카드 클릭 = 필터 |
3825
+ | `notice` | `ReactNode` | | | 목록 위 고지 |
3826
+ | `emptyActions` | `ReactNode` | | | 필터 없는 빈 상태의 다음 행동 (필터된 빈 상태는 필터 지우기 유지) |
3827
+ | `header` | `ReactNode` | | | 헤더 슬롯 |
3828
+ | `actions` | `ReactNode` | | | 액션 슬롯 |
3829
+ | `toolbar` | `ReactNode` | | | 통계와 필터 사이 컨트롤 (스코프 세그먼트 등) |
3830
+ | `inspector` | `ReactNode` | | | 인스펙터 내용 |
3831
+ | `inspectorOpen` | `boolean` | Yes | | 인스펙터 열림 |
3832
+ | `onInspectorClose` | `() => void` | Yes | | 인스펙터 닫기 |
3833
+ | `inspectorTitle` | `ReactNode` | | | 인스펙터 제목 |
3834
+ | `inspectorDescription` | `ReactNode` | | | 인스펙터 설명 |
3835
+ | `inspectorActions` | `ReactNode` | | | 인스펙터 헤더 컨트롤 |
3836
+ | `inspectorFooter` | `ReactNode` | | | 인스펙터 하단 |
3837
+ | `inspectorWidth` | `"sm" \| "md" \| "lg"` | | | push 레이아웃 폭 |
3838
+ | `page` | `number` | | 1 | 현재 페이지 |
3839
+ | `pageSize` | `number` | | 50 | 페이지 크기 |
3840
+ | `totalCount` | `number` | | | 필터 반영 총 개수 |
3841
+ | `onPageChange` | `(page: number) => void` | | | 페이지 변경 |
3842
+ | `selectedKeys` | `string[]` | | | 선택된 행 |
3843
+ | `onSelectionChange` | `(keys: string[]) => void` | | | 선택 변경. 필터·페이지가 바뀌면 프레임이 비웁니다 |
3844
+ | `bulkActions` | `FloatingAction[]` | | | 일괄 작업 |
3845
+ | `onBulkAction` | `(actionId: string) => void` | | | 일괄 작업 실행 |
3846
+ | `error` | `ReactNode` | | | 읽기 실패. 빈 목록과 다른 답 |
3847
+ | `onRetry` | `() => void` | | | 재시도 |
3848
+ | `labels` | `CatalogFrameLabels` | | | 빈/필터된 빈/에러 문구 |
3849
+
3850
+ **CatalogRowActions:**
3851
+
3852
+ | Prop | Type | Required | Default | Description |
3853
+ | -------------- | ------------------------- | -------- | ------- | ------------------------------------------------------- |
3854
+ | `item` | `T` | Yes | | 이 행의 항목 |
3855
+ | `actions` | `CatalogRowAction<T>[]` | Yes | | 행 액션 |
3856
+ | `visibleCount` | `number` | | 2 | 오버플로 전에 노출할 개수. available 필터링 후에 적용됨 |
3857
+ | `labels` | `CatalogRowActionsLabels` | | | 그룹·오버플로 라벨 |
3858
+
3859
+ **CatalogCellControls:**
3860
+
3861
+ | Prop | Type | Required | Default | Description |
3862
+ | ---------- | ----------- | -------- | ------- | ---------------------------------- |
3863
+ | `children` | `ReactNode` | Yes | | 행 클릭으로 새면 안 되는 셀 컨트롤 |
3864
+
3561
3865
  ### Surface Layer