@reopt-ai/opt-ui 1.13.0 → 1.14.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 (37) hide show
  1. package/COMPONENT_CATALOG.md +426 -58
  2. package/README.md +9 -7
  3. package/dist/core/index.cjs +1 -1
  4. package/dist/core/index.d.cts +2 -2
  5. package/dist/core/index.d.ts +2 -2
  6. package/dist/core/index.js +1 -1
  7. package/dist/docs/02-components/01-core.md +225 -26
  8. package/dist/docs/02-components/02-visuals.md +1 -1
  9. package/dist/docs/02-components/03-shells.md +203 -32
  10. package/dist/docs/02-components/04-surfaces.md +1 -1
  11. package/dist/docs/02-components/index.md +4 -4
  12. package/dist/{field-sidebar-Dz7J4ett.d.ts → field-sidebar-CJ4HxP8D.d.cts} +1 -1
  13. package/dist/{field-sidebar-D-rwuN_w.d.cts → field-sidebar-DnhpcT2A.d.ts} +1 -1
  14. package/dist/{field-sidebar-CxxSK4JO.cjs → field-sidebar-ePqFX6MN.cjs} +13 -12
  15. package/dist/{field-sidebar-CRdToHRO.js → field-sidebar-mSVCMAZp.js} +13 -12
  16. package/dist/id-registry.cjs +8 -0
  17. package/dist/id-registry.js +8 -0
  18. package/dist/id-registry.json +17 -0
  19. package/dist/index.cjs +756 -51
  20. package/dist/index.d.cts +196 -10
  21. package/dist/index.d.ts +196 -10
  22. package/dist/index.js +750 -53
  23. package/dist/{key-pad-menu-0KWOnELe.cjs → key-pad-menu-BgtSL3xe.cjs} +9 -6
  24. package/dist/{key-pad-menu-DMmbQ1jF.js → key-pad-menu-CqFI6la9.js} +9 -6
  25. package/dist/{key-pad-menu-BOVu97bj.d.cts → key-pad-menu-D6pYzaj-.d.cts} +12 -3
  26. package/dist/{key-pad-menu-NlZ9zNF8.d.ts → key-pad-menu-Yh7Fpb8m.d.ts} +12 -3
  27. package/dist/meta.cjs +430 -19
  28. package/dist/meta.js +430 -19
  29. package/dist/shells/index.cjs +1 -1
  30. package/dist/shells/index.d.cts +1 -1
  31. package/dist/shells/index.d.ts +1 -1
  32. package/dist/shells/index.js +1 -1
  33. package/dist/{text-truncate-eMzvU_7k.d.cts → text-truncate-Bbul-jMD.d.cts} +1 -30
  34. package/dist/{text-truncate-eMzvU_7k.d.ts → text-truncate-Bbul-jMD.d.ts} +1 -30
  35. package/dist/theme/server.d.cts +2 -2
  36. package/dist/theme/server.d.ts +2 -2
  37. package/package.json +2 -2
@@ -2,7 +2,7 @@
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.13.0 -->
5
+ <!-- Version: 1.14.0 -->
6
6
 
7
7
  ## Quick Stats
8
8
 
@@ -10,9 +10,9 @@
10
10
  | --------- | ------- |
11
11
  | Core | 74 |
12
12
  | Visuals | 0 |
13
- | Shells | 95 |
13
+ | Shells | 96 |
14
14
  | Surfaces | 0 |
15
- | **Total** | **169** |
15
+ | **Total** | **170** |
16
16
 
17
17
  ## Component Selection Guide
18
18
 
@@ -211,7 +211,7 @@
211
211
  | Component | Description | Key Exports |
212
212
  | --------- | ----------- | ----------- |
213
213
 
214
- ## Shell Components (95)
214
+ ## Shell Components (96)
215
215
 
216
216
  ### Navigation & Layout
217
217
 
@@ -343,35 +343,36 @@
343
343
 
344
344
  ### Other
345
345
 
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` |
366
- | SchemaTree | 쿼리할 있는 테이블과 컬럼을 타입 글리프와 함께 보여주는 트리. 테이블·컬럼을 함께 검색하고, 이름을 커서에 삽입하거나 테이블을 미리보기합니다. | `SchemaTree` |
367
- | QueryToolbar | 실행 버튼 하나가 상태를 말하는 쿼리 툴바. 변경됨/현재/실행 중을 색과 문구로 구분하고, 실행 중이면 취소로 바뀌며, 선택 영역·전체 실행은 분할 버튼 뒤에 둡니다. | `QueryToolbar` |
368
- | QueryOutputPane | 쿼리 결과가 놓이는 출력 패널. 대기·실행 중·오류·취소·완료 상태를 그리고, 완료는 표·차트·좌우 분할로 전환하며, 상태바에 수·경과·읽은 바이트·절단 여부를 남깁니다. | `QueryOutputPane` |
369
- | QueryResultChart | 결과 행을 차트로 그리는 빌더. 문자·날짜 컬럼을 축으로, 숫자 컬럼을 값으로 고르고, 숫자면 숫자로 보여줍니다. 설정은 호출자가 들고 있어 저장 쿼리와 함께 보관됩니다. | `QueryResultChart` |
370
- | QueryFiltersMenu | 기간과 속성 조건을 데이터로 들고 {filters} 플레이스홀더로 SQL에 전달하는 메뉴. 플레이스홀더가 없으면 조건이 적용되지 않는다고 경고하고 삽입 버튼을 제공합니다. | `QueryFiltersMenu` |
371
- | QueryVariablesMenu | 실행마다 바뀌는 값을 이름 붙여 두는 변수 메뉴. SQL은 {variables.name}으로 참조하고 치환은 호출자가 합니다. | `QueryVariablesMenu` |
372
- | QueryHistoryList | 실행 이력 목록. 실행의 성공/실패, 시각, 수, 경과를 보여주고 편집기로 되돌리거나 다시 실행합니다. | `QueryHistoryList` |
373
- | SaveQueryDialog | 쿼리에 이름·설명·공개 여부를 붙여 저장하는 다이얼로그. 편집기에 문장이 여럿이면 어느 문장을 저장할지 넘겨 보며 고릅니다. | `SaveQueryDialog` |
374
- | QueryWorkspace | 스키마·편집기·출력의 3-pane 쿼리 워크스페이스. 패널은 리사이즈되고 사이드바는 접히며, storageKey로 레이아웃을 기억합니다. 툴바·편집기·출력은 슬롯입니다. | `QueryWorkspace` |
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
+ | CriteriaBuilder | 도메인 무관 2단계 조건 트리 편집기. 그룹 AND/OR, 순서·복제·부정·오류를 셸이 맡고 조건 문장은 소비자가 Expression 칩으로 렌더링합니다. | `CriteriaBuilder`, `criteriaBuilderMove`, `criteriaBuilderDuplicate`, `criteriaBuilderRemove`, `criteriaBuilderInsert`, `criteriaBuilderRemoveGroup`, `criteriaBuilderDuplicateGroup`, `criteriaGroupLetter` |
352
+ | EventTimeline | 이벤트를 순서로 읽히게 하는 타임라인. 인접 이벤트 사이의 경과 시간을 라벨링하고, 속성 페이로드를 제자리에서 펼치며, 세션 단위 그룹핑을 지원한다. | `EventTimeline` |
353
+ | ScoreBreakdown | 합성 점수를 축별로 분해해 보여준다. 총점과 함께 축의 값·가중치·의미를 노출해 '43'을 판정이 아니라 발견으로 만든다. | `ScoreBreakdown` |
354
+ | Flyout | 목록을 화면에 레코드를 옆에서 보여주는 상세 패널. 모달이 아니다 — 포커스 트랩·aria-modal·inert 없이 Escape로 닫고 포커스를 되돌린다. | `Flyout` |
355
+ | AuditTimeline | 변경 이력 타임라인. 액션별 색상 코딩 + 확장 가능한 diff 뷰. | `AuditTimeline` |
356
+ | ChatSidebar | AI 채팅 사이드바. 대화 목록, 검색, 대화 버튼. | `ChatSidebar` |
357
+ | ChatInput | 채팅 입력 컴포넌트. 자동 리사이즈 textarea, 파일 첨부, 모델/스타일 Select. | `ChatInput` |
358
+ | ChatMessageList | 채팅 메시지 목록. 역할별 말풍선, 타이핑 인디케이터, 자동 스크롤. | `ChatMessageList` |
359
+ | TimeRangeControl | date math(now-7d, now/d) 기반 시간 범위 컨트롤. quick select, 프리셋/최근 사용, 명시적 Update, 자동 갱신, 이동·확대/축소 버튼을 제공합니다. | `TimeRangeControl`, `DEFAULT_TIME_PRESETS` |
360
+ | TimeSeriesPanel | 시간 범위 컨트롤과 시계열 차트를 단위로 묶은 패널. 드래그 줌과 히스토리(되돌리기), 범례 토글을 포함합니다. | `TimeSeriesPanel` |
361
+ | LogTable | 계속 도착하는 로그용 윈도잉 테이블. 컬럼 정의 기반, 상단 삽입 스크롤 위치 보존, follow 상태 보고, 값 즉시 필터, 밀도·정렬을 지원합니다. | `LogTable` |
362
+ | QueryBar | 검색과 필터를 입력으로 합친 쿼리 바. field:value, -부정, (a or b), 비교 연산, 필드·값 자동완성, 절(clause) 칩을 지원합니다. | `QueryBar` |
363
+ | FieldSidebar | 데이터에 어떤 필드가 있고 필드가 무슨 값을 갖는지 보여주는 사이드바. 분포 막대, 컬럼으로 승격, 값 기준 포함/제외 필터를 제공합니다. | `FieldSidebar` |
364
+ | InspectorLayout | 목록과 인스펙터의 2-pane 레이아웃. 넓으면 밀어내고(push) 좁으면 덮으며(overlay), 닫을 포커스를 열었던 자리로 되돌립니다. | `InspectorLayout` |
365
+ | QueryFilterBar | QueryBar와 필터 버튼이 하나의 Query를 공유합니다. 버튼은 상태를 갖지 않고 Query를 읽어 활성 여부를 계산합니다. | `QueryFilterBar`, `hasActiveQuery` |
366
+ | CatalogFrame | 카탈로그 목록의 공통 뼈대. 헤더·통계·고지·필터·인스펙터·페이지네이션·일괄 작업과 빈/에러 상태를 담고, 필터나 페이지가 바뀌면 선택을 비웁니다. | `CatalogFrame`, `CatalogRowActions`, `CatalogCellControls` |
367
+ | SchemaTree | 쿼리할 있는 테이블과 컬럼을 타입 글리프와 함께 보여주는 트리. 테이블·컬럼을 함께 검색하고, 이름을 커서에 삽입하거나 테이블을 미리보기합니다. | `SchemaTree` |
368
+ | QueryToolbar | 실행 버튼 하나가 상태를 말하는 쿼리 툴바. 변경됨/현재/실행 중을 색과 문구로 구분하고, 실행 중이면 취소로 바뀌며, 선택 영역·전체 실행은 분할 버튼 뒤에 둡니다. | `QueryToolbar` |
369
+ | QueryOutputPane | 쿼리 결과가 놓이는 출력 패널. 대기·실행 중·오류·취소·완료 상태를 그리고, 완료는 표·차트·좌우 분할로 전환하며, 상태바에수·경과·읽은 바이트·절단 여부를 남깁니다. | `QueryOutputPane` |
370
+ | QueryResultChart | 결과 행을 차트로 그리는 빌더. 문자·날짜 컬럼을 축으로, 숫자 컬럼을 값으로 고르고, 숫자면 숫자로 보여줍니다. 설정은 호출자가 들고 있어 저장 쿼리와 함께 보관됩니다. | `QueryResultChart` |
371
+ | QueryFiltersMenu | 기간과 속성 조건을 데이터로 들고 {filters} 플레이스홀더로 SQL에 전달하는 메뉴. 플레이스홀더가 없으면 조건이 적용되지 않는다고 경고하고 삽입 버튼을 제공합니다. | `QueryFiltersMenu` |
372
+ | QueryVariablesMenu | 실행마다 바뀌는 값을 이름 붙여 두는 변수 메뉴. SQL은 {variables.name}으로 참조하고 치환은 호출자가 합니다. | `QueryVariablesMenu` |
373
+ | QueryHistoryList | 실행 이력 목록. 실행의 성공/실패, 시각, 수, 경과를 보여주고 편집기로 되돌리거나 다시 실행합니다. | `QueryHistoryList` |
374
+ | SaveQueryDialog | 쿼리에 이름·설명·공개 여부를 붙여 저장하는 다이얼로그. 편집기에 문장이 여럿이면 어느 문장을 저장할지 넘겨 보며 고릅니다. | `SaveQueryDialog` |
375
+ | QueryWorkspace | 스키마·편집기·출력의 3-pane 쿼리 워크스페이스. 패널은 리사이즈되고 사이드바는 접히며, storageKey로 레이아웃을 기억합니다. 툴바·편집기·출력은 슬롯입니다. | `QueryWorkspace` |
375
376
 
376
377
  ## Surface Components (0)
377
378
 
@@ -739,7 +740,7 @@
739
740
  | Prop | Type | Required | Default | Description |
740
741
  | ------------- | ------------------------- | -------- | ------- | --------------------------------------------------------------------------------------- |
741
742
  | `open` | `boolean` | | | 제어 모드: 열림 상태 |
742
- | `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 **⚠️ deprecated since 1.12.5 — use `onOpenChange` instead** |
743
+ | `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 **⚠️ deprecated since 1.13.0 — use `onOpenChange` instead** |
743
744
  | `defaultOpen` | `boolean` | | false | 비제어 모드: 초기 열림 상태 |
744
745
 
745
746
  **DisclosureTrigger:**
@@ -773,7 +774,7 @@
773
774
  | `variant` | `"underline" \| "workspace"` | | | 탭 프레임 형태. workspace는 편집기 탭(문서/쿼리처럼 열고 닫히며 상태를 갖는 작업 단위) |
774
775
  | `defaultSelectedId` | `string` | | | 초기 선택된 탭 ID |
775
776
  | `selectedId` | `string \| null` | | | 제어 모드: 선택된 탭 ID |
776
- | `setSelectedId` | `(id: string \| null) => void` | | | 제어 모드: 탭 변경 핸들러 **⚠️ deprecated since 1.12.5 — use `onSelectedIdChange` instead** |
777
+ | `setSelectedId` | `(id: string \| null) => void` | | | 제어 모드: 탭 변경 핸들러 **⚠️ deprecated since 1.13.0 — use `onSelectedIdChange` instead** |
777
778
 
778
779
  **TabList:**
779
780
 
@@ -810,6 +811,27 @@
810
811
  | `Home` | 첫 번째 탭으로 이동 |
811
812
  | `End` | 마지막 탭으로 이동 |
812
813
 
814
+ **Examples:**
815
+
816
+ _이름 있는 두 패널:_
817
+
818
+ ```tsx
819
+ import { TabsRoot, TabList, Tab, TabPanel } from "@reopt-ai/opt-ui";
820
+
821
+ export function Example() {
822
+ return (
823
+ <TabsRoot defaultSelectedId="overview">
824
+ <TabList aria-label="프로젝트 정보">
825
+ <Tab id="overview">개요</Tab>
826
+ <Tab id="activity">활동</Tab>
827
+ </TabList>
828
+ <TabPanel tabId="overview">프로젝트 요약</TabPanel>
829
+ <TabPanel tabId="activity">최근 활동</TabPanel>
830
+ </TabsRoot>
831
+ );
832
+ }
833
+ ```
834
+
813
835
  #### Select
814
836
 
815
837
  **Import:** `import { SelectRoot } from "@reopt-ai/opt-ui"`
@@ -843,7 +865,7 @@
843
865
  | ----------- | ----------- | -------- | ------- | ------------------------------------------------------------------------------ |
844
866
  | `children` | `ReactNode` | Yes | | SelectItem 목록 |
845
867
  | `sameWidth` | `boolean` | | true | 트리거와 같은 너비 |
846
- | `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.12.5 — use `sideOffset` instead** |
868
+ | `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
847
869
  | `className` | `string` | | | 기본 스타일 오버라이드 |
848
870
 
849
871
  **SelectItem:**
@@ -896,7 +918,7 @@ import {
896
918
  | Prop | Type | Required | Default | Description |
897
919
  | --------- | ------------------------- | -------- | ------- | --------------------------------------------------------------------------------------- |
898
920
  | `open` | `boolean` | | | 제어 모드: 열림 상태 |
899
- | `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 **⚠️ deprecated since 1.12.5 — use `onOpenChange` instead** |
921
+ | `setOpen` | `(open: boolean) => void` | | | 제어 모드: 상태 변경 핸들러 **⚠️ deprecated since 1.13.0 — use `onOpenChange` instead** |
900
922
 
901
923
  **DialogDisclosure:**
902
924
 
@@ -988,7 +1010,7 @@ import {
988
1010
 
989
1011
  | Prop | Type | Required | Default | Description |
990
1012
  | ------------------ | ------------------------- | -------- | ------- | ------------------------------------------------------------------------------- |
991
- | `setValue` | `(value: string) => void` | | | 입력값 변경 핸들러 **⚠️ deprecated since 1.12.5 — use `onValueChange` instead** |
1013
+ | `setValue` | `(value: string) => void` | | | 입력값 변경 핸들러 **⚠️ deprecated since 1.13.0 — use `onValueChange` instead** |
992
1014
  | `resetValueOnHide` | `boolean` | | false | 팝오버 닫힐 때 입력값 리셋 |
993
1015
 
994
1016
  **ComboboxInput:**
@@ -1005,7 +1027,7 @@ import {
1005
1027
  | ----------- | ----------- | -------- | ------- | ---------------------------------------------------------------------------- |
1006
1028
  | `children` | `ReactNode` | Yes | | ComboboxItem/Group 목록 |
1007
1029
  | `sameWidth` | `boolean` | | true | 입력과 같은 너비 |
1008
- | `gutter` | `number` | | 4 | 입력과의 간격 (px) **⚠️ deprecated since 1.12.5 — use `sideOffset` instead** |
1030
+ | `gutter` | `number` | | 4 | 입력과의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
1009
1031
  | `className` | `string` | | | 기본 스타일 오버라이드 |
1010
1032
 
1011
1033
  **ComboboxItem:**
@@ -1083,7 +1105,7 @@ import {
1083
1105
  | Prop | Type | Required | Default | Description |
1084
1106
  | ----------- | ----------- | -------- | ------- | ------------------------------------------------------------------------------ |
1085
1107
  | `children` | `ReactNode` | Yes | | MenuItem 목록 |
1086
- | `gutter` | `number` | | 8 | 트리거와의 간격 (px) **⚠️ deprecated since 1.12.5 — use `sideOffset` instead** |
1108
+ | `gutter` | `number` | | 8 | 트리거와의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
1087
1109
  | `className` | `string` | | | 기본 스타일 오버라이드 |
1088
1110
 
1089
1111
  **MenuItem:**
@@ -1236,7 +1258,7 @@ import {
1236
1258
  | ----------- | ----------- | -------- | ------- | ------------------------------------------------------------------------------ |
1237
1259
  | `children` | `ReactNode` | Yes | | FormSelectItem 목록 |
1238
1260
  | `sameWidth` | `boolean` | | true | 트리거와 같은 너비 |
1239
- | `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.12.5 — use `sideOffset` instead** |
1261
+ | `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
1240
1262
 
1241
1263
  **FormSelectItem:**
1242
1264
 
@@ -1494,6 +1516,21 @@ import { Button } from "@reopt-ai/opt-ui";
1494
1516
  | `progress` | `number` | | | 원형 프로그레스 값 (0-100). 설정 시 dot 무시 |
1495
1517
  | `progressSize` | `number` | | 16 | 프로그레스 링 SVG 크기 (px) |
1496
1518
 
1519
+ **Examples:**
1520
+
1521
+ _텍스트가 있는 상태:_
1522
+
1523
+ ```tsx
1524
+ import { Badge } from "@reopt-ai/opt-ui";
1525
+ export function Example() {
1526
+ return (
1527
+ <Badge variant="success" dot>
1528
+ 동기화 완료
1529
+ </Badge>
1530
+ );
1531
+ }
1532
+ ```
1533
+
1497
1534
  #### Spinner
1498
1535
 
1499
1536
  **Import:** `import { Spinner } from "@reopt-ai/opt-ui"`
@@ -1502,6 +1539,17 @@ import { Button } from "@reopt-ai/opt-ui";
1502
1539
  | ------ | ---------------------- | -------- | ------- | ----------- |
1503
1540
  | `size` | `"sm" \| "md" \| "lg"` | | "md" | 스피너 크기 |
1504
1541
 
1542
+ **Examples:**
1543
+
1544
+ _이름 있는 로딩 표시:_
1545
+
1546
+ ```tsx
1547
+ import { Spinner } from "@reopt-ai/opt-ui";
1548
+ export function Example() {
1549
+ return <Spinner size="sm" aria-label="검색 결과 불러오는 중" />;
1550
+ }
1551
+ ```
1552
+
1505
1553
  #### Alert
1506
1554
 
1507
1555
  **Import:** `import { Alert } from "@reopt-ai/opt-ui"`
@@ -1514,6 +1562,21 @@ import { Button } from "@reopt-ai/opt-ui";
1514
1562
  | `dismissible` | `boolean` | | false | 닫기 버튼 표시 여부 |
1515
1563
  | `onDismiss` | `() => void` | | | 닫기 버튼 클릭 핸들러 |
1516
1564
 
1565
+ **Examples:**
1566
+
1567
+ _재시도 가능한 오류 안내:_
1568
+
1569
+ ```tsx
1570
+ import { Alert } from "@reopt-ai/opt-ui";
1571
+ export function Example() {
1572
+ return (
1573
+ <Alert variant="error" title="저장하지 못했습니다">
1574
+ 연결 상태를 확인한 뒤 다시 저장하세요.
1575
+ </Alert>
1576
+ );
1577
+ }
1578
+ ```
1579
+
1517
1580
  #### Input
1518
1581
 
1519
1582
  **Import:** `import { Input } from "@reopt-ai/opt-ui"`
@@ -1582,6 +1645,27 @@ const store = useFormStore({ defaultValues: { name: "" } });
1582
1645
  | `size` | `"sm" \| "md" \| "lg"` | | "md" | 스위치 크기 |
1583
1646
  | `disabled` | `boolean` | | | 비활성화 상태 |
1584
1647
 
1648
+ **Examples:**
1649
+
1650
+ _제어되는 알림 설정:_
1651
+
1652
+ ```tsx
1653
+ "use client";
1654
+ import { useState } from "react";
1655
+ import { Switch } from "@reopt-ai/opt-ui";
1656
+ export function Example() {
1657
+ const [enabled, setEnabled] = useState(false);
1658
+ return (
1659
+ <Switch
1660
+ label="이메일 알림"
1661
+ hint="새 댓글을 이메일로 받습니다"
1662
+ checked={enabled}
1663
+ onChange={setEnabled}
1664
+ />
1665
+ );
1666
+ }
1667
+ ```
1668
+
1585
1669
  #### Skeleton
1586
1670
 
1587
1671
  **Import:** `import { Skeleton } from "@reopt-ai/opt-ui"`
@@ -1615,6 +1699,21 @@ const store = useFormStore({ defaultValues: { name: "" } });
1615
1699
  | `rows` | `number` | | 5 | 테이블 행 수 |
1616
1700
  | `columns` | `number` | | 4 | 테이블 열 수 |
1617
1701
 
1702
+ **Examples:**
1703
+
1704
+ _목록 로딩 자리 확보:_
1705
+
1706
+ ```tsx
1707
+ import { SkeletonTable } from "@reopt-ai/opt-ui";
1708
+ export function Example() {
1709
+ return (
1710
+ <section aria-label="목록 불러오는 중" aria-busy="true">
1711
+ <SkeletonTable rows={3} columns={4} />
1712
+ </section>
1713
+ );
1714
+ }
1715
+ ```
1716
+
1618
1717
  #### Textarea
1619
1718
 
1620
1719
  **Import:** `import { Textarea } from "@reopt-ai/opt-ui"`
@@ -1628,6 +1727,25 @@ const store = useFormStore({ defaultValues: { name: "" } });
1628
1727
  | `resize` | `"none" \| "vertical" \| "horizontal" \| "both"` | | "vertical" | 크기 조절 방향 |
1629
1728
  | `rows` | `number` | | 4 | 표시 줄 수 |
1630
1729
 
1730
+ **Examples:**
1731
+
1732
+ _설명 입력:_
1733
+
1734
+ ```tsx
1735
+ import { Textarea } from "@reopt-ai/opt-ui";
1736
+ export function Example() {
1737
+ return (
1738
+ <Textarea
1739
+ label="변경 이유"
1740
+ name="reason"
1741
+ hint="검토자가 알아야 할 내용을 적어주세요"
1742
+ rows={4}
1743
+ resize="vertical"
1744
+ />
1745
+ );
1746
+ }
1747
+ ```
1748
+
1631
1749
  #### Avatar
1632
1750
 
1633
1751
  **Import:** `import { Avatar } from "@reopt-ai/opt-ui"`
@@ -1651,6 +1769,22 @@ const store = useFormStore({ defaultValues: { name: "" } });
1651
1769
  | `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | | "md" | 아바타 크기 |
1652
1770
  | `children` | `ReactNode` | Yes | | Avatar 요소들 |
1653
1771
 
1772
+ **Examples:**
1773
+
1774
+ _이미지 없이 사용자 표시:_
1775
+
1776
+ ```tsx
1777
+ import { Avatar, AvatarGroup } from "@reopt-ai/opt-ui";
1778
+ export function Example() {
1779
+ return (
1780
+ <AvatarGroup max={3}>
1781
+ <Avatar name="김민수" />
1782
+ <Avatar name="이지수" />
1783
+ </AvatarGroup>
1784
+ );
1785
+ }
1786
+ ```
1787
+
1654
1788
  #### Progress
1655
1789
 
1656
1790
  **Import:** `import { Progress } from "@reopt-ai/opt-ui"`
@@ -1681,6 +1815,17 @@ const store = useFormStore({ defaultValues: { name: "" } });
1681
1815
  | `label` | `string` | | | 접근성 레이블 |
1682
1816
  | `indeterminate` | `boolean` | | false | 값을 알 수 없는 진행 상태 |
1683
1817
 
1818
+ **Examples:**
1819
+
1820
+ _업로드 진행률:_
1821
+
1822
+ ```tsx
1823
+ import { Progress } from "@reopt-ai/opt-ui";
1824
+ export function Example() {
1825
+ return <Progress value={35} max={100} aria-label="파일 업로드" />;
1826
+ }
1827
+ ```
1828
+
1684
1829
  #### Meter
1685
1830
 
1686
1831
  **Import:** `import { Meter } from "@reopt-ai/opt-ui"`
@@ -1843,6 +1988,22 @@ import {
1843
1988
  | `orientation` | `"horizontal" \| "vertical"` | | "vertical" | 레이아웃 방향 |
1844
1989
  | `label` | `string` | | | 그룹 레이블 |
1845
1990
 
1991
+ **Examples:**
1992
+
1993
+ _복수 선택 그룹:_
1994
+
1995
+ ```tsx
1996
+ import { Checkbox, CheckboxGroup } from "@reopt-ai/opt-ui";
1997
+ export function Example() {
1998
+ return (
1999
+ <CheckboxGroup label="알림 채널" defaultValue={["email"]}>
2000
+ <Checkbox value="email" label="이메일" />
2001
+ <Checkbox value="push" label="푸시" />
2002
+ </CheckboxGroup>
2003
+ );
2004
+ }
2005
+ ```
2006
+
1846
2007
  #### RadioGroup
1847
2008
 
1848
2009
  **Import:** `import { RadioGroup } from "@reopt-ai/opt-ui"`
@@ -1962,27 +2123,27 @@ import {
1962
2123
 
1963
2124
  **Import:** `import { ConditionBuilder } from "@reopt-ai/opt-ui"`
1964
2125
 
1965
- | Prop | Type | Required | Default | Description |
1966
- | --------------------- | --------------------------------------- | -------- | ------------------ | -------------------------------------- |
1967
- | `groups` | `ConditionGroup[]` | Yes | | 조건 그룹 배열 |
1968
- | `onChange` | `(groups: ConditionGroup[]) => void` | Yes | | 그룹 변경 핸들러 |
1969
- | `properties` | `string[]` | | | 선택 가능한 속성 목록 (기본 10개 제공) |
1970
- | `label` | `string` | | | 빌더 레이블 |
1971
- | `nested` | `boolean` | | false | 중첩 AND/OR 그룹 활성화 |
1972
- | `maxDepth` | `number` | | 3 | 최대 중첩 깊이 |
1973
- | `conditionTypes` | `Record<string, ConditionTypeRenderer>` | | | 이질적 조건 타입 렌더러 레지스트리 |
1974
- | `onPreview` | `(groups: ConditionGroup[]) => void` | | | 조건 변경 시 미리보기 콜백 |
1975
- | `previewCount` | `number` | | | 매치 카운트 표시 (toLocaleString 포맷) |
1976
- | `addNestedGroupLabel` | `string` | | "Add nested group" | 중첩 그룹 추가 버튼 텍스트 |
2126
+ | Prop | Type | Required | Default | Description |
2127
+ | --------------------- | --------------------------------------- | -------- | ------------------ | ------------------------------------------------------------------------------ |
2128
+ | `groups` | `ConditionGroup[]` | Yes | | 조건 그룹 배열 |
2129
+ | `onChange` | `(groups: ConditionGroup[]) => void` | Yes | | 그룹 변경 핸들러 |
2130
+ | `properties` | `string[]` | | | 선택 가능한 속성 목록 (기본 10개 제공) |
2131
+ | `label` | `string` | | | 빌더 레이블 |
2132
+ | `nested` | `boolean` | | false | 중첩 AND/OR 그룹 활성화 |
2133
+ | `maxDepth` | `number` | | 3 | 최대 중첩 깊이 |
2134
+ | `conditionTypes` | `Record<string, ConditionTypeRenderer>` | | | 이질적 조건 타입 렌더러 레지스트리 |
2135
+ | `onPreview` | `(groups: ConditionGroup[]) => void` | | | 조건 변경 시 미리보기 콜백 |
2136
+ | `previewCount` | `number` | | | 매치 카운트 표시 (toLocaleString 포맷) |
2137
+ | `labels` | `ConditionBuilderLabels` | | | 미리보기 문구 오버라이드 (previewSuffix, formatPreview). 기본은 영어 "matches" |
2138
+ | `addNestedGroupLabel` | `string` | | "Add nested group" | 중첩 그룹 추가 버튼 텍스트 |
1977
2139
 
1978
2140
  #### Popover
1979
2141
 
1980
2142
  **Import:** `import { PopoverRoot } from "@reopt-ai/opt-ui"`
1981
2143
 
1982
- | Prop | Type | Required | Default | Description |
1983
- | ----------- | -------- | -------- | ------- | ------------------------------------------------------------------------------ |
1984
- | `gutter` | `number` | | 8 | 트리거와의 간격 (px) **⚠️ deprecated since 1.12.5 — use `sideOffset` instead** |
1985
- | `className` | `string` | | | 커스텀 CSS 클래스 |
2144
+ | Prop | Type | Required | Default | Description |
2145
+ | ----------- | -------- | -------- | ------- | ----------------- |
2146
+ | `className` | `string` | | | 커스텀 CSS 클래스 |
1986
2147
 
1987
2148
  **Keyboard Shortcuts:**
1988
2149
 
@@ -1991,6 +2152,30 @@ import {
1991
2152
  | `Esc` | 팝오버 닫기 |
1992
2153
  | `Enter / Space` | 트리거 활성화 |
1993
2154
 
2155
+ **Examples:**
2156
+
2157
+ _보조 설명 열고 닫기:_
2158
+
2159
+ ```tsx
2160
+ import {
2161
+ PopoverRoot,
2162
+ PopoverTrigger,
2163
+ PopoverContent,
2164
+ PopoverClose,
2165
+ } from "@reopt-ai/opt-ui";
2166
+ export function Example() {
2167
+ return (
2168
+ <PopoverRoot>
2169
+ <PopoverTrigger>공유 안내</PopoverTrigger>
2170
+ <PopoverContent>
2171
+ <p>초대받은 사용자만 문서를 볼 수 있습니다.</p>
2172
+ <PopoverClose>닫기</PopoverClose>
2173
+ </PopoverContent>
2174
+ </PopoverRoot>
2175
+ );
2176
+ }
2177
+ ```
2178
+
1994
2179
  #### DropdownMenu
1995
2180
 
1996
2181
  **Import:** `import { DropdownMenu } from "@reopt-ai/opt-ui"`
@@ -1999,7 +2184,7 @@ import {
1999
2184
 
2000
2185
  | Prop | Type | Required | Default | Description |
2001
2186
  | -------- | -------- | -------- | ------- | ------------------------------------------------------------------------------ |
2002
- | `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.12.5 — use `sideOffset` instead** |
2187
+ | `gutter` | `number` | | 4 | 트리거와의 간격 (px) **⚠️ deprecated since 1.13.0 — use `sideOffset` instead** |
2003
2188
 
2004
2189
  **DropdownItem:**
2005
2190
 
@@ -2288,6 +2473,21 @@ const MyDashboard = createBlock<MyDashboardProps>(
2288
2473
  | `children` | `ReactNode` | Yes | | 감싸는 콘텐츠 |
2289
2474
  | `label` | `string` | | "Loading…" | 로딩 텍스트 |
2290
2475
 
2476
+ **Examples:**
2477
+
2478
+ _기존 결과를 유지하는 갱신 표시:_
2479
+
2480
+ ```tsx
2481
+ import { LoadingOverlay } from "@reopt-ai/opt-ui";
2482
+ export function Example() {
2483
+ return (
2484
+ <LoadingOverlay loading label="목록 새로고침 중">
2485
+ <p>이전 조회 결과</p>
2486
+ </LoadingOverlay>
2487
+ );
2488
+ }
2489
+ ```
2490
+
2291
2491
  #### StarRating
2292
2492
 
2293
2493
  **Import:** `import { StarRating } from "@reopt-ai/opt-ui"`
@@ -2779,6 +2979,24 @@ import { DataTable } from "@reopt-ai/opt-ui";
2779
2979
  | `toast` | `ToastMessage` | Yes | | 토스트 메시지 객체 |
2780
2980
  | `onDismiss` | `() => void` | Yes | | 닫기 핸들러 |
2781
2981
 
2982
+ **Examples:**
2983
+
2984
+ _사용자 동작의 결과 알림:_
2985
+
2986
+ ```tsx
2987
+ "use client";
2988
+ import { Button, ToastProvider, toast } from "@reopt-ai/opt-ui";
2989
+ export function Example() {
2990
+ return (
2991
+ <ToastProvider>
2992
+ <Button onClick={() => toast.success("알림 동작을 확인했습니다")}>
2993
+ 알림 테스트
2994
+ </Button>
2995
+ </ToastProvider>
2996
+ );
2997
+ }
2998
+ ```
2999
+
2782
3000
  #### DesignGuidePanel
2783
3001
 
2784
3002
  **Import:** `import { DesignGuidePanel } from "@reopt-ai/opt-ui"`
@@ -3187,6 +3405,103 @@ const filters = [
3187
3405
  | `onCancel` | `() => void` | | | 취소 콜백 |
3188
3406
  | `labels` | `ReportBuilderLabels` | | | UI 텍스트 커스터마이징 |
3189
3407
 
3408
+ #### CriteriaBuilder
3409
+
3410
+ **Import:** `import { CriteriaBuilder } from "@reopt-ai/opt-ui"`
3411
+ **Dependencies:** segmented-control (core), dropdown-menu (core), button (core), callout (core), empty-state (core), kbd (core)
3412
+
3413
+ | Prop | Type | Required | Default | Description |
3414
+ | --------------------- | -------------------------------------------------------------------------------- | -------- | ------- | ------------------------------------------------------------------------------------------ |
3415
+ | `value` | `CriteriaBuilderValue<TCriterion>` | Yes | | 조건 트리. { logic, groups: [{ id, logic, criteria }] } |
3416
+ | `onChange` | `(next: CriteriaBuilderValue<TCriterion>) => void` | Yes | | 트리 변경 핸들러 |
3417
+ | `kinds` | `CriteriaBuilderKindOption[]` | Yes | | 조건 추가 메뉴 항목. group으로 섹션을 나누고 negatedLabel이 있으면 부정 항목을 따로 냅니다 |
3418
+ | `createCriterion` | `(kind: string, negate: boolean) => TCriterion` | Yes | | 메뉴 선택으로 만들 초기 조건. 고유 id를 돌려줘야 합니다 |
3419
+ | `renderCriterion` | `(criterion: TCriterion, api: CriteriaRenderApi<TCriterion>) => React.ReactNode` | Yes | | 조건 한 줄의 편집 가능한 문장 렌더러 |
3420
+ | `cloneCriterion` | `(criterion: TCriterion) => TCriterion` | | | 복제 시 만들 사본. 기본은 새 id를 붙인 얕은 복사 |
3421
+ | `createGroupId` | `() => string` | | | 셸이 만드는 그룹의 id. 기본 group-N |
3422
+ | `errors` | `Record<string, string>` | | | 조건 id 또는 그룹 id별 오류 메시지 |
3423
+ | `maxGroups` | `number` | | 10 | 그룹 최대 수 |
3424
+ | `maxCriteriaPerGroup` | `number` | | 20 | 그룹당 조건 최대 수 |
3425
+ | `allowNegation` | `boolean` | | true | 조건별 부정 토글 표시 |
3426
+ | `disabled` | `boolean` | | false | 전체 비활성화 |
3427
+ | `aside` | `React.ReactNode` | | | 넓은 화면에서 트리 옆, 좁은 화면에서 아래에 놓이는 미리보기 슬롯 |
3428
+ | `labels` | `CriteriaBuilderLabels` | | | i18n용 라벨 오버라이드 (기본 한국어) |
3429
+ | `className` | `string` | | | 루트 CSS 클래스 |
3430
+ | `aria-label` | `string` | | | 빌더 접근성 이름 |
3431
+
3432
+ **Keyboard Shortcuts:**
3433
+
3434
+ | Keys | Action |
3435
+ | ---- | ----------------------------------- |
3436
+ | `A` | 포커스된 그룹에 조건 추가 메뉴 열기 |
3437
+ | `G` | 그룹 추가 |
3438
+
3439
+ **Examples:**
3440
+
3441
+ _이벤트 조건 세그먼트:_
3442
+
3443
+ ```tsx
3444
+ "use client";
3445
+ import { useState } from "react";
3446
+ import {
3447
+ CriteriaBuilder,
3448
+ Expression,
3449
+ ExpressionGroup,
3450
+ type CriteriaBuilderValue,
3451
+ } from "@reopt-ai/opt-ui";
3452
+
3453
+ interface Criterion {
3454
+ id: string;
3455
+ kind: string;
3456
+ negate?: boolean;
3457
+ event: string;
3458
+ }
3459
+
3460
+ let seq = 0;
3461
+
3462
+ export function Example() {
3463
+ const [value, setValue] = useState<CriteriaBuilderValue<Criterion>>({
3464
+ logic: "and",
3465
+ groups: [
3466
+ {
3467
+ id: "g1",
3468
+ logic: "and",
3469
+ criteria: [{ id: "c1", kind: "performed", event: "purchase" }],
3470
+ },
3471
+ ],
3472
+ });
3473
+ return (
3474
+ <CriteriaBuilder
3475
+ value={value}
3476
+ onChange={setValue}
3477
+ kinds={[
3478
+ {
3479
+ kind: "performed",
3480
+ label: "이벤트를 수행함",
3481
+ negatedLabel: "이벤트를 수행하지 않음",
3482
+ },
3483
+ ]}
3484
+ createCriterion={(kind, negate) => ({
3485
+ id: `c${++seq}`,
3486
+ kind,
3487
+ negate,
3488
+ event: "",
3489
+ })}
3490
+ renderCriterion={(criterion, api) => (
3491
+ <ExpressionGroup>
3492
+ <Expression
3493
+ description={criterion.negate ? "수행하지 않음" : "수행함"}
3494
+ value={criterion.event || "이벤트 선택"}
3495
+ invalid={api.invalid || criterion.event === ""}
3496
+ onClick={() => api.update({ event: "purchase" })}
3497
+ />
3498
+ </ExpressionGroup>
3499
+ )}
3500
+ />
3501
+ );
3502
+ }
3503
+ ```
3504
+
3190
3505
  #### InsightsPanel
3191
3506
 
3192
3507
  **Import:** `import { InsightsPanel } from "@reopt-ai/opt-ui"`
@@ -3213,6 +3528,27 @@ const filters = [
3213
3528
  | `presets` | `TimePresetDef[]` | | | 빠른 프리셋 목록 (Today, Last 7d 등) |
3214
3529
  | `labels` | `TimeRangeSelectorLabels` | | | i18n용 라벨 오버라이드 |
3215
3530
 
3531
+ **Examples:**
3532
+
3533
+ _제어되는 조회 기간:_
3534
+
3535
+ ```tsx
3536
+ "use client";
3537
+ import { useState } from "react";
3538
+ import { TimeRangeSelector, type DateRange } from "@reopt-ai/opt-ui";
3539
+ export function Example() {
3540
+ const [range, setRange] = useState<DateRange>({ start: null, end: null });
3541
+ return (
3542
+ <TimeRangeSelector
3543
+ value={range}
3544
+ onChange={setRange}
3545
+ labels={{ title: "조회 기간", placeholder: "기간 선택" }}
3546
+ presets={[{ label: "최근 7일", days: 7 }]}
3547
+ />
3548
+ );
3549
+ }
3550
+ ```
3551
+
3216
3552
  #### ExportButton
3217
3553
 
3218
3554
  **Import:** `import { ExportButton } from "@reopt-ai/opt-ui"`
@@ -3243,6 +3579,38 @@ const filters = [
3243
3579
  | `percentageFractionDigits` | `number` | | 1 | percentage 포맷 시 소수점 자리수 |
3244
3580
  | `loading` | `boolean` | | false | 로딩 시 스켈레톤 표시 |
3245
3581
 
3582
+ **Examples:**
3583
+
3584
+ _의미가 다른 통계 비교:_
3585
+
3586
+ ```tsx
3587
+ import { SummaryRow } from "@reopt-ai/opt-ui";
3588
+ export function Example() {
3589
+ return (
3590
+ <SummaryRow
3591
+ columns={2}
3592
+ stats={[
3593
+ {
3594
+ id: "orders",
3595
+ title: "주문",
3596
+ value: "120",
3597
+ change: "+10%",
3598
+ trend: "up",
3599
+ },
3600
+ {
3601
+ id: "errors",
3602
+ title: "오류",
3603
+ value: "2",
3604
+ change: "-50%",
3605
+ trend: "down",
3606
+ polarity: "negative",
3607
+ },
3608
+ ]}
3609
+ />
3610
+ );
3611
+ }
3612
+ ```
3613
+
3246
3614
  #### EventTimeline
3247
3615
 
3248
3616
  **Import:** `import { EventTimeline } from "@reopt-ai/opt-ui"`